<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在上一篇文章中,我與你介紹了在 Flutter 中實現數據持久化的三種方式,即文件、SharedPreferences 與數據庫。 其中,文件適用于字符串或者二進制流的數據持久化,我們可以根據訪問頻次,決定將它存在臨時目錄或是文檔目錄。而 SharedPreferences 則適用于存儲小型鍵值對信息,可以應對一些輕量配置緩存的場景。數據庫則適用于頻繁變化的、結構化的對象存取,可以輕松應對數據的增刪改查。 依托于與 Skia 的深度定制及優化,Flutter 給我們提供了很多關于渲染的控制和支持,能夠實現絕對的跨平臺應用層渲染一致性。但對于一個應用而言,除了應用層視覺顯示和對應的交互邏輯處理之外,有時還需要原生操作系統(Android、iOS)提供的底層能力支持。比如,我們前面提到的數據持久化,以及推送、攝像頭硬件調用等。 由于 Flutter 只接管了應用渲染層,因此這些系統底層能力是無法在 Flutter 框架內提供支持的;而另一方面,Flutter 還是一個相對年輕的生態,因此原生開發中一些相對成熟的 Java、C++ 或 Objective-C 代碼庫,比如圖片處理、音視頻編解碼等,可能在 Flutter 中還沒有相關實現。 因此,為了解決調用原生系統底層能力以及相關代碼庫復用問題,Flutter 為開發者提供了一個輕量級的解決方案,即邏輯層的方法通道(Method Channel)機制。基于方法通道,我們可以將原生代碼所擁有的能力,以接口形式暴露給 Dart,從而實現 Dart 代碼與原生代碼的交互,就像調用了一個普通的 Dart API 一樣。 接下來,我就與你詳細講述 Flutter 的方法通道機制吧。 ## 方法通道 Flutter 作為一個跨平臺框架,提供了一套標準化的解決方案,為開發者屏蔽了操作系統的差異。但,Flutter 畢竟不是操作系統,因此在某些特定場景下(比如推送、藍牙、攝像頭硬件調用時),也需要具備直接訪問系統底層原生代碼的能力。為此,Flutter 提供了一套靈活而輕量級的機制來實現 Dart 和原生代碼之間的通信,即方法調用的消息傳遞機制,而方法通道則是用來傳遞通信消息的信道。 一次典型的方法調用過程類似網絡調用,由作為客戶端的 Flutter,通過方法通道向作為服務端的原生代碼宿主發送方法調用請求,原生代碼宿主在監聽到方法調用的消息后,調用平臺相關的 API 來處理 Flutter 發起的請求,最后將處理完畢的結果通過方法通道回發至 Flutter。調用過程如下圖所示: :-: ![](https://img.kancloud.cn/a8/a5/a8a5cec456e66323e045318d7c5f4d9c_1020x784.png) 圖 1 方法通道示意圖 從上圖中可以看到,方法調用請求的處理和響應,在 Android 中是通過 FlutterView,而在 iOS 中則是通過 FlutterViewController 進行注冊的。FlutterView 與 FlutterViewController 為 Flutter 應用提供了一個畫板,使得構建于 Skia 之上的 Flutter 通過繪制即可實現整個應用所需的視覺效果。因此,它們不僅是 Flutter 應用的容器,同時也是 Flutter 應用的入口,自然也是注冊方法調用請求最合適的地方。 接下來,我通過一個例子來演示如何使用方法通道實現與原生代碼的交互。 ## 方法通道使用示例 在實際業務中,提示用戶跳轉到應用市場(iOS 為 App Store、Android 則為各類手機應用市場)去評分是一個高頻需求,考慮到 Flutter 并未提供這樣的接口,而跳轉方式在 Android 和 iOS 上各不相同,因此我們需要分別在 Android 和 iOS 上實現這樣的功能,并暴露給 Dart 相關的接口。 我們先來看看作為客戶端的 Flutter,怎樣實現一次方法調用請求。 ### Flutter 如何實現一次方法調用請求? 首先,我們需要確定一個唯一的字符串標識符,來構造一個命名通道;然后,在這個通道之上,Flutter 通過指定方法名“openAppMarket”來發起一次方法調用請求。 可以看到,這和我們平時調用一個 Dart 對象的方法完全一樣。因為方法調用過程是異步的,所以我們需要使用非阻塞(或者注冊回調)來等待原生代碼給予響應。 ~~~ // 聲明 MethodChannel const platform = MethodChannel('samples.chenhang/utils'); // 處理按鈕點擊 handleButtonClick() async{ int result; // 異常捕獲 try { // 異步等待方法通道的調用結果 result = await platform.invokeMethod('openAppMarket'); } catch (e) { result = -1; } print("Result:$result"); } ~~~ 需要注意的是,與網絡調用類似,方法調用請求有可能會失敗(比如,Flutter 發起了原生代碼不支持的 API 調用,或是調用過程出錯等),因此我們需要把發起方法調用請求的語句用 try-catch 包裝起來。 調用方的實現搞定了,接下來就需要在原生代碼宿主中完成方法調用的響應實現了。由于我們需要適配 Android 和 iOS 兩個平臺,所以我們分別需要在兩個平臺上完成對應的接口實現。 ### 在原生代碼中完成方法調用的響應 首先,**我們來看看 Android 端的實現方式**。在上一小結最后我提到,在 Android 平臺,方法調用的處理和響應是在 Flutter 應用的入口,也就是在 MainActivity 中的 FlutterView 里實現的,因此我們需要打開 Flutter 的 Android 宿主 App,找到 MainActivity.java 文件,并在其中添加相關的邏輯。 調用方與響應方都是通過命名通道進行信息交互的,所以我們需要在 onCreate 方法中,創建一個與調用方 Flutter 所使用的通道名稱一樣的 MethodChannel,并在其中設置方法處理回調,響應 openAppMarket 方法,打開應用市場的 Intent。同樣地,考慮到打開應用市場的過程可能會出錯,我們也需要增加 try-catch 來捕獲可能的異常: ~~~ protected void onCreate(Bundle savedInstanceState) { ... // 創建與調用方標識符一樣的方法通道 new MethodChannel(getFlutterView(), "samples.chenhang/utils").setMethodCallHandler( // 設置方法處理回調 new MethodCallHandler() { // 響應方法請求 @Override public void onMethodCall(MethodCall call, Result result) { // 判斷方法名是否支持 if(call.method.equals("openAppMarket")) { try { // 應用市場 URI Uri uri = Uri.parse("market://details?id=com.hangchen.example.flutter_module_page.host"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 打開應用市場 activity.startActivity(intent); // 返回處理結果 result.success(0); } catch (Exception e) { // 打開應用市場出現異常 result.error("UNAVAILABLE", " 沒有安裝應用市場 ", null); } }else { // 方法名暫不支持 result.notImplemented(); } } }); } ~~~ 現在,方法調用響應的 Android 部分已經搞定,接下來我們來看一下**iOS 端的方法調用響應如何實現。** 在 iOS 平臺,方法調用的處理和響應是在 Flutter 應用的入口,也就是在 Applegate 中的 rootViewController(即 FlutterViewController)里實現的,因此我們需要打開 Flutter 的 iOS 宿主 App,找到 AppDelegate.m 文件,并添加相關邏輯。 與 Android 注冊方法調用響應類似,我們需要在 didFinishLaunchingWithOptions: 方法中,創建一個與調用方 Flutter 所使用的通道名稱一樣的 MethodChannel,并在其中設置方法處理回調,響應 openAppMarket 方法,通過 URL 打開應用市場: ~~~ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 創建命名方法通道 FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"samples.chenhang/utils" binaryMessenger:(FlutterViewController *)self.window.rootViewController]; // 往方法通道注冊方法調用處理回調 [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { // 方法名稱一致 if ([@"openAppMarket" isEqualToString:call.method]) { // 打開 App Store(本例打開微信的 URL) [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/xy/app/foo/id414478124"]]; // 返回方法處理結果 result(@0); } else { // 找不到被調用的方法 result(FlutterMethodNotImplemented); } }]; ... } ~~~ 這樣,iOS 端的方法調用響應也已經實現了。 接下來,我們就可以在 Flutter 應用里,通過調用 openAppMarket 方法,實現打開不同操作系統提供的應用市場功能了。 需要注意的是,在原生代碼處理完畢后將處理結果返回給 Flutter 時,**我們在 Dart、Android 和 iOS 分別用了三種數據類型**:Android 端返回的是 java.lang.Integer、iOS 端返回的是 NSNumber、Dart 端接收到返回結果時又變成了 int 類型。這是為什么呢? 這是因為在使用方法通道進行方法調用時,由于涉及到跨系統數據交互,Flutter 會使用 StandardMessageCodec 對通道中傳輸的信息進行類似 JSON 的二進制序列化,以標準化數據傳輸行為。這樣在我們發送或者接收數據時,這些數據就會根據各自系統預定的規則自動進行序列化和反序列化。看到這里,你是不是對這樣類似網絡調用的方法通道技術有了更深刻的印象呢。? 對于上面提到的例子,類型為 java.lang.Integer 或 NSNumber 的返回值,先是被序列化成了一段二進制格式的數據在通道中傳輸,然后當該數據傳遞到 Flutter 后,又被反序列化成了 Dart 語言中的 int 類型的數據。 關于 Android、iOS 和 Dart 平臺間的常見數據類型轉換,我總結成了下面一張表格,幫助你理解與記憶。你只要記住,像 null、布爾、整型、字符串、數組和字典這些基本類型,是可以在各個平臺之間以平臺定義的規則去混用的,就可以了。 :-: ![](https://img.kancloud.cn/c6/f1/c6f1148978fabe62e4089d7877ecb1e7_931x420.png) 圖 2 Android、iOS 和 Dart 平臺間的常見數據類型轉換 ## 總結 好了,今天的分享就到這里,我們來總結一下主要內容吧。 方法通道解決了邏輯層的原生能力復用問題,使得 Flutter 能夠通過輕量級的異步方法調用,實現與原生代碼的交互。一次典型的調用過程由 Flutter 發起方法調用請求開始,請求經由唯一標識符指定的方法通道到達原生代碼宿主,而原生代碼宿主則通過注冊對應方法實現、響應并處理調用請求,最后將執行結果通過消息通道,回傳至 Flutter。 ?需要注意的是,方法通道是非線程安全的。這意味著原生代碼與 Flutter 之間所有接口調用必須發生在主線程。Flutter 是單線程模型,因此自然可以確保方法調用請求是發生在主線程(Isolate)的;而原生代碼在處理方法調用請求時,如果涉及到異步或非主線程切換,需要確保回調過程是在原生系統的 UI 線程(也就是 Android 和 iOS 的主線程)中執行的,否則應用可能會出現奇怪的 Bug,甚至是 Crash。 我把今天分享所涉及到的知識點打包到了[GitHub](https://github.com/cyndibaby905/26_native_method)中,你可以下載下來,反復運行幾次,加深理解。 ## 思考題 最后,我給你留下一道思考題吧。 請擴展方法通道示例,讓 openAppMarket 支持傳入 AppID 和包名,使得我們可以跳轉到任意一個 App 的應用市場。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看