日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

架構設計說明

該篇文章,介紹并記錄在大前端混合架構開發中的重要細節和流程。通過在Android/ target=_blank class=infotextkey>安卓原生工程中集成兩大主流混合框架React Native、Flutter,以及ReactJs[Vue],集成三類模塊module的架構的混合設計。并分別在這些主流技術棧的業務創作中,自己造輪子、使用新穎架構設計及核心技術去實現。并在編碼過程中還會創造常用工具,沉浸式狀態欄、底部導航欄、Flutter熱更新、Flutter多入口、

Tab1 Tab2 Tab3 Tab4 Tab5
仿招商銀行首頁 仿即時通訊 仿工商銀行首頁 仿抖音我的頁面 仿唯品會分類

在原生工程中創建一個首頁,在首頁中使用五個TAB

  • TAB1,使用原生JAVA+Kotlin編碼,仿招商銀行首頁,使用優秀架構設計,完成列表各個模塊的獨立解耦。
  • TAB2,使用原生Java+Kotlin編碼,仿微信,通過Android Socket實現IM的即時通訊。
  • TAB3,使用React Native編碼,仿工商銀行首頁。
  • TAB4,使用Flutter編碼,仿抖音我的頁面。
  • TAB5,使用ReactJs編碼,仿唯品會分類頁面。

創建安卓原生工程

Android Studio版本 Gradle 插件版本 Gradle 版本 Kotlin版本 JDK 版本 其他
3.6 3.6.0 gradle-6.7.1-all.zip(原5.6.4) 1.5.31 JDK11 compileSdkVersion 31、buildToolsVersion “30.0.0” 、minSdkVersion 21、targetSdkVersion 30

創建Flutter

Android Studio版本 Gradle 插件版本 Gradle 版本 JDK 版本 其他
3.6 3.6.0 gradle-5.6.4-all.zip JDK11 compileSdkVersion 31、buildToolsVersion “30.0.0” 、minSdkVersion 21、targetSdkVersion 30

集成嵌入原生工程

詳盡集成介紹,請移步查看

創建React Native

與創建Flutter相比較,React Native工程創建時,復雜很多。創建時候會遇到創建失敗問題,成功創建后,啟動Metro服務也會遇到報錯問題。而這些問題都與nodejs版本React Naitve版本有關。請詳細閱讀官方搭建環境的文檔,

React Native 創建指令:npx react-native init hibrid_rn --version 0.67.0
Metro服務啟動指令:npx react-native start
Android apk 編譯安裝指令:yarn android

Node版本 React Native版本 JDK 版本 說明
v16.17.0 0.67.0 JDK11 詳細版本號,請移步查看代碼

解決RN報錯問題

若有報錯,下面

如下報錯信息,則是node版本號使用不當導致~
/node_modules/@react-native-community/cli/build/commands/doctor/healthchecks/index.js:48
} catch {}
^
SyntaxError: Unexpected token {
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:617:28)
at Object.Module._extensions…js (module.js:664:10)
… … …

若有報錯,下面
Could not find react-native-0.71.0-rc.0-debug.aar (com.facebook.react:react-native:0.71.0-rc.0).

Could not determine the dependencies of task ':App:lintVitalRelease'.
> Could not resolve all artifacts for configuration ':app:debugCompileClasspath'.
   > Could not find react-native-0.71.0-rc.0-debug.aar (com.facebook.react:react-native:0.71.0-rc.0).

解決方案, 指定ReactNative確定版本號!!修改ReactNativeapp/build.gradle
implementation "com.facebook.react:react-native:+" 改為implementation "com.facebook.react:react-native:0.67.0"

若有報錯,下面
Execution failed for task ':app:mergeDebugNativeLibs'.
More than one file was found with OS independent path 'lib/x86_64/libfbjni.so'

在這里插入圖片描述
解決方案, 在app/build.gradle android{} 中添加截圖中報錯的如lib/x86_64/libfbjni.so

packagingOptions {
        pickFirst 'lib/x86/libc++_shared.so'
        pickFirst 'lib/x86_64/libc++_shared.so'
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
        pickFirst 'lib/x86/libfbjni.so'
        pickFirst 'lib/x86_64/libfbjni.so' // 截圖中有這個報錯,這里添加該so修復
        pickFirst 'lib/armeabi-v7a/libfbjni.so'
        pickFirst 'lib/arm64-v8a/libfbjni.so'
    }

集成嵌入原生工程

Groovy

// 【app/build.gradle】下進行配置
// 【配置共三步】rn第一步配置:start
project.ext.react = [
        entryFile   : "index.android.js",
        enableHermes: false,
        bundleInDebug:true,
        bundleInBeta:true
]

def enableHermes = project.ext.react.get("enableHermes", false);
def jscFlavor = 'org.webkit:android-jsc:+'

def safeExtGet(prop, fallback) {
    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
// 【配置共三步】rn第一步配置:end
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    ......
    // 【配置共三步】rn第二步配置:start
    if (enableHermes) {
        def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
    implementation "com.facebook.react:react-native:+" // From node_modules
    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
    // 【配置共三步】rn第二步配置:end
}

// 【project/build.gradle】下進行配置
allprojects {
    repositories {
        ......
        // 【配置共三步】rn第三步配置:start
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/../hibrid_rn/node_modules/react-native/android"
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../hibrid_rn/node_modules/jsc-android/dist")
        }
        //【配置共三步】rn第三步配置:end
        
    }
}

參數字段說明:

  • entryFile : "index.android.js",表示配置加載安卓資源入口文件名稱。
  • def hermesPath = "../../hibrid_rn/node_modules/hermesvm/android/",表示當enableHermes==true時,引入執行引擎Hermes。否則,使用JavaScriptCore執行引擎。

Hermes 是一個可選的 React Native 功能。如果要啟用Hermes,需要確保 React Native項目的版本在0.60.2版本 以上,并且還需要對android/app/build.gradle 做以下更改。我們這里配置enableHermes: false

Groovy
project.ext.react = [
  entryFile: "index.js",
  enableHermes: true // 配置開啟Hermes引擎
]

RN集成后,啟動報錯

在原生工程中集成了RN之后,將React Native作為原生工程Activity下LayoutView的一部分,測試集成狀態。發現從Native啟動React Native報以下錯誤~

ReactNative: Exception in native call java.lang.RuntimeException: Unable to load script. Make sure you're either running Metro (run 'npx react-native start') or that your bundle 'rn/index.android.bundle' is packaged correctly for release.

在這里插入圖片描述
報錯信息說,Metro服務未啟動,或者說找不到bundle資源包。而事實是當前Metro服務已啟動,且直接啟動React Native工程是OK的。對此尋到以下兩種解決方案 :

  • 對當前React Native工程代碼進行打包,并將打包后的bundle資源拷貝到Native工程的/main/assets/rn目錄下。然后在Native運行則無問題。
  • VSCode終端執行打包指令: react-native bundle --platform android --dev false --entry-file index.js --bundle-output ../HybridArcPro/app/src/main/assets/rn/index.android.bundle --assets-dest ../HybridArcPro/app/src/main/res/
  • 非打包處理。需要對Native和React Native端同時進行配置。①對安裝的debug包APP配置服務IP和端口號。②配置網絡權限,application標簽中配置 tools:targetApi="28" android:allowBackup="true"。③啟動Metro服務。

在這里插入圖片描述

底部導航欄架構設計

使用java語言,自定義首頁底部導航欄布局控件(下圖實現效果+導航源碼),自定義UML介紹~
在這里插入圖片描述

  • TabBtnLayoutBottomNav 底部導航欄布局自定義View。繼承自FrameLayout,實現自接口ITabLayout。底部導航欄布局,內部擺放TabBtnBottom
  • TabBtnBottom底部導航欄布局中的單個Tab。繼承自RelativeLayout,實現自I接口ITab(ITab繼承了點擊事件的監聽接口OnTabSelectedListener)。
  • TabBtnLayoutBottomNav 內部封裝單個Tab集合List<OnTabSelectedListener>(包含所有TabBtnBottom和TabBtnLayoutBottomNav添加的監聽OnTabSelectedListener),當用戶點擊Tab時,點擊事件通過TabBtnBottom.setOnClickListener觸發集合List的遍歷,此時將點擊事件傳遞給每個TabBtnBottomz,同時TabBtnLayoutBottomNav添加的監聽回調。由此單個Tab和TabBtnLayoutBottomNav產生了點擊事件的關聯,并能為集成fragment點擊切換顯示做下伏筆。
    在這里插入圖片描述在這里插入圖片描述
  • TabBtnFragmentLayout,顯示fragment頁面的**自定義布局控件**,放在布局文件TabBtnLayoutBottomNav中。由TabBtnLayoutBottomNav添加的監聽回調index,方法setCurrentItem獲得指示并顯示相應fragment頁面。
  • TabBtnFragmentAdapter,顯示fragment頁面的適配器類。具體指示顯示fragment頁面邏輯,實現在方法instantiateItem中。
    在這里插入圖片描述

原生仿招商銀行首頁

原生Android Socket 即時通訊

React Native仿工商銀行首頁

使用RN仿工商銀行首頁(圖標自己費勁吧啦找的),然后實現StatusBar和TitleBar**滑動漸變**效果。此處由原生啟動并打開RN,效果如下~
在這里插入圖片描述

原生傳遞props初始對象,RN使用

// React Native中配置bundle
val bundle = Bundle()
rnBundle.putCharSequence("device-info","設備信息對象")
rnBundle.putCharSequence("state","用戶登錄狀態")
mReactRootView!!.startReactApplication(mReactInstanceManager, "hibrid_rn", bundle)

// 在對應的ReactNative的Coponent中獲取,則可通過this.props得到!

原生與RN通信

已實現效果介紹

在Native端橋接類JRNBridge.kt中定義了一個調用安卓Toast的方法,供ReactNative端調用。效果如下
在這里插入圖片描述

開發中注意事項

這里以本項目作為示例,介紹下在實現RN和C端通信時,開發步驟邏輯。
1, 邏輯源碼C端中定義橋接類工具JRNBridge.kt。橋接類繼承自ReactContextBaseJavaModule.java,實現方法getName —— 獲取到的name會在ReactNative端使用,

// bridge/index.js
import {NativeModules} from 'react-native'
module.exports = NativeModules.RNBridge  // 這里的 RNBridge 就是getName得到。

2, ReactNative和C端Native進行通信的方法,需要加注解@ReactMethod

3, 創建JReactPackage.kt 繼承ReactPackage.kt,重寫方法createNativeModules和createViewManagers。重寫方法createNativeModules是將JReactPackage添加到NativeModule列表為之后注冊。

CreateNativeModules CreateViewManagers
ReactNative調用Native方法時重寫并添加NativeModule Native UI,作為ReactNative UI是重寫并添加ViewManager

4, 將MainReactPackage()和JReactPackage()添加注冊到ReactInstanceManager中。
其中MainReactPackage()及JReactPackage()必須, 否則報錯'StatusBarManager' could not be found. Verify that a module by this name is registered in the native binary.
在這里插入圖片描述

JReactPackage()否則報錯, 找不到RNBridge.toast({toast:'正在取號中,請稍后...'})

5, ReactNative中導出在NativeModules中已注冊的JRNBridge。然后在ReactNative各個地方引入并使用。
在這里插入圖片描述

ReactNative端源碼

import RNBridge from '@bridge/index'
<TouchableOpacity onPress={()=>{RNBridge.toast({toast:'正在取號中,請稍后...'})}} >

Flutter仿抖音我的頁面

Flutter熱更新

Flutter熱更新,通過動態.so文件的加載實現。

.so文件動態加載實現思路
以反射修改FlutterLoader.java類FlutterApplicationInfo.aotSharedLibraryName的值,從而修改了FlutterLoader將要加載的原libapp.solibapp**.so。之后,將用來替換的libapp**.so拷貝到原libapp.so所在的目錄即可。拷貝的方式,如首先打包一個新的release-apk,然后解壓提取出此時的libapp.so文件(修改名稱為libapp**.so),放到目錄assets/下。之后,當執行代碼拷貝時,會將assets/目錄下的so包拷貝到新指定的將會加載的libapp.so所在的目錄,然后則順理成章完成熱更新。

在這里插入圖片描述

在這里插入圖片描述

多FlutterEngine引擎創建,多dart入口實現

flutter一個投資理財頁,作為第二個dart入口。并通過下面定義的對應引擎啟開。
在這里插入圖片描述

多FlutterEngine引擎創建

通過FlutterEngine創建引擎實例對象。創建時傳入的JFlutterLoader,重新定義了原FlutterLoader獲取dart代碼包的方式。之后,根據給定的DartEntrypoint開始執行Dart代碼。并緩存已創建的Flutter引擎實例。其中傳入給DartEntrypointmoduleName是dart入口名稱findAppBundlePath是flutter資產目錄flutterAssetsDir

// 初始化,根據moduleName(dart入口名稱)創建多個Flutter引擎
private fun initFlutterEngine(context: Context, moduleName: String): FlutterEngine? {
    var flutterEngine:FlutterEngine = FlutterEngine(context, JFlutterLoader.get(), FlutterJNI())
        
    flutterEngine.dartExecutor
            .executeDartEntrypoint(DartExecutor.DartEntrypoint(JFlutterLoader.get().findAppBundlePath(), moduleName))
    FlutterEngineCache.getInstance().put(moduleName, flutterEngine) // 緩存起來
    return flutterEngine
}

多dart入口創建

// 在flutter的dart代碼中main.dart
// 至少有一個默認入口,如 'main'
void main() {
  runApp(const MyApp());
  init();
}

// 此時,可仿照默認入口,通過注解,創建多個不同的dart入口 - 工行的'投資理財'詳情頁面
@pragma('vm:entry-point')
void finance() {
  runApp(FinanceEntryApp());
}

結合Flutter源碼,分析從原生端啟動Flutter

原生與Flutter通信

在這里插入圖片描述

類型 說明
MethodChannel 用于傳遞方法調用invokeMethod一次性通信:如Flutter調用埋點功能。

這里且介紹MethodChannel,在Native與Flutter間如何通信~Flutter側發送,Native側接收處理。
Flutter側發送,結合源碼看,通過創建一個MethodChannel實例并指定渠道名稱name。且兩側的name須一致相同。然后使用MethodChannel實例調用執行方法invokeMethod,該方法傳入Native側將被調用方法名稱method及通信消息內容arguments。之后,便啟動了由Flutter向Native側傳遞調用。
Native側接收處理,創建一個與Flutter側渠道名稱name相同的MethodChannel實例。使用MethodChannel實例調用執行方法setMethodCallHandler,用以匹配Flutter側方法名稱method接收處理Flutter側發送來的信息。詳盡設計實現,請移步查看

分享到:
標簽:Android
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定