主頁 > 移動端開發 > 一款零侵入的高效Flutter混合堆疊管理方案,你值得擁有!

一款零侵入的高效Flutter混合堆疊管理方案,你值得擁有!

2021-06-16 18:01:28 移動端開發

在實際的作業場景中,我們很難從零開始用純Flutter去建設一個專案,也正是因為這樣,Native+Flutter混合堆疊跳轉管理使我們在混合開發的時候不得不首先考慮的問題,因為我們很難保證不會遇到下面的情況,

那么如何做技術選型困惑了不少想要做混開的同學,畢竟Flutter的生態還不是十分成熟,現成的解決方案和輪子并不多,而且還不一定好用,要么資源占用過高,要么侵入性太強,好在經過這幾天的摸索,總結出來了一套方案,供大家學習參考,相互交流,


按照國際慣例,我先介紹一下目前市場上的一些解決方案以及存在的問題,

本文章基于Flutter版本:2.2 & Platform:Android

1.Google官方(多引擎方案)

即每次使用一個新的FlutterEngine來渲染Widget樹,雖然Flutter 2.0之后的創建FlutterEngine的開銷大大降低,但是依然沒有解決每個FlutterEngine是一個單獨isolate,如果需要Flutter①和Flutter②之間互動資料的話,將會非常麻煩,我們同樣無法保證他們之間不會進行資料互動,因此Pass,

2.大名鼎鼎的閑魚flutter_boost(單引擎方案)

flutter_boost最近發布了3.0的bate版本,摒棄了2.0版本對引擎的侵入(贊!),但是依然存在不少問題:

①:高居不下的未關閉issues與回復不及時之間的矛盾(可以理解,竟然還是有作業要做的),

②:復雜的設計,在出現使用問題的時候,通過改flutter_boost原始碼解決的成本很高,

③:flutter方面耦合度較高,我必須使用flutter_boost提供的一系列Route相關的工具和Widget才能達到混合堆疊跳轉的效果,如果我以后想要更換框架,那對代碼的修改將是海量的,

于是乎成功把我勸退,

3.哈嘍單車團隊的flutter_thrio(單引擎方案)

該庫的優劣作者已經說得很詳細了,這里就不再贅述,感興趣的朋友可以進傳送門親自查看,

4.位元組跳動團隊的Isolate復用方案和騰訊心悅團隊的TRouter方案

很可惜,目前這兩個方案并沒有開源出來,但很可能位元組團隊的方案的侵入性相當高,


既然沒有現成的方案,那就擼起袖子造一個,先來一個混合堆疊跳轉的效果演示:

專案地址:github.com/wangkunhui/…

那么現在開始把上面的功能實作吧,

首先,要確定最終實作的目標,然后一步步朝著目標去完善:

目標一:復用FlutterEngine,避免額外的資源開銷與FlutterEngine之間的通信成本,

目標二:Flutter Widget之間的跳轉無需通過Native層控制(flutter_boost需要),

目標三:每個打開的Flutter能且只能管理自己內部的堆疊,當前Flutter的Widget全部出堆疊后,退出當前Flutter,

目標四:支持Flutter帶引數打開Native頁面(回傳值也可以支持,但目前還未添加進去),

根據這些目標設計出來的模型圖如下:

上圖是依次交叉打開的5個Activity的堆疊資訊示意圖,可以分為三列,具體解釋如下:

左側的是Activity的堆疊資訊,其中第二個和第四個掛載了Flutter,又分別打開了幾個Flutter的Widget,

中間是FlutterEngine中的Widget堆疊示意圖,因為復用FlutterEngine的原因,Widget A到Widget P都存在于一個堆疊中,而處在最底部的是一個空白的HostWidget,不負責任何業務邏輯,其目的就是保證其上方的業務相關的Widget能正常被Pop出堆疊(因為Flutter Navigator的最后一個Widget是無法被Pop的),

右側是對中間的FlutterEngine中Widget堆疊的管線資訊說明,就是那些Widget是關聯在那些HostActivity實體上的,為的就是能夠控制我對Widget進行退堆疊操作的時候,知道退到哪個Widget時需要finish掉關聯的Activity,

如果上面的描述不是很直觀的話,那我舉個栗子說明,我在HostActivity 實體2里打開兩個Flutter頁面,Widget O和Widget P,當這兩個Widget完成自己的任務后,就要進行退出操作,當我退出Widget P時,界面就變成了Widget O,這是沒問題的,然后我繼續退出WIdget O,如果不進行特殊處理的話,FlutterEngine將會展示Widget N,這顯然不是我們想要的,我們預期的結果是此時要finish掉HostActivity 實體2,展示NativeOneActivity,想要達到這樣的效果,就需要認為的把FlutterEngine 堆疊里面在不同HostActivity實體中顯示的Widget進行特殊的區分,

好了,理論作業已經做完了,接下來就是愉快的Coding時光,我們面臨任務清單有以下幾個:

一、如何對FlutterEngine進行復用?

二、FlutterActivity、FlutterFragment還是FlutterView?

三、如何監聽FlutterEngine的堆疊變化資訊?

四、如何把監聽到的堆疊資訊同步到宿主Activity實體?

五、如何處理宿主Activity和Flutter頁面的同步?


第一個問題,首先實體化FlutterEngine:

/**
 * 初始化FlutterEngine
 * @param context 背景關系
 * @param block 初始化狀態回呼 0 不需要初始化 1 開始初始化 2 初始化完畢
 */
@Synchronized
fun initFlutterEngine(context: Context, block: (status: Int) -> Unit) {
    //判斷快取已存在
    if (!FlutterEngineCache.getInstance().contains(FLUTTER_ENGINE)) {

        block(1)
        //初始化FlutterEngine
        var engine = FlutterEngine(context.applicationContext)
        //初始化BasicMessageChannel
        messageChannel = BasicMessageChannel(
             engine.dartExecutor,
             FLUTTER_MIX_STACK_CHANNEL,
             StringCodec.INSTANCE
        )
        //添加訊息監聽
        messageChannel?.setMessageHandler(messageHandler)

        this.initCallback = block
        //開始運行dart代碼
        engine.dartExecutor.executeDartEntrypoint(
               DartExecutor.DartEntrypoint.createDefault()
        )					
        //快取FlutterEngine
        FlutterEngineCache.getInstance().put(FLUTTER_ENGINE, engine)
    } else {
        block(0)
    }
}

FlutterEngineCache已經幫我們封裝好了FlutterEngine的快取功能,不過要怎么使用這個快取呢?

官方提供的FlutterActivity類中有一個withCachedEngine的靜態方法,可以幫助我們獲取使用快取的Intent實體,也可以繼承FlutterActivity重寫getCachedEngineId方法,達到FlutterEngine復用的效果,直接啟動FlutterActivity就可以加載Flutter頁面,非常的簡單方便,但是如果有一些稍微復雜的場景時,FlutterActivity就有些不太夠用了,

第二個問題,Flutter 2.0 為我們提供了三種Flutter容器,分別是FlutterActivity(FlutterFragmentActivity)、FlutterFragment和FlutterView,以滿足我們不同場景下的使用,從這三個類注釋檔案的豐富程度上來看,官方是非常推薦我們直接使用FlutterActivity的,簡單看下原始碼就能發現,不管是FlutterActivity還是FLutterFragment,都是基于FlutterView實作的,如果專案有指定的基類需要繼承或者要實作原生UI+Flutter UI的情況,或是想要更早的預熱Flutter的Widget,FlutterView無疑會更靈活一些,所以這里我就選擇使用了普通的Activity+FlutterView,偽代碼如下:

class HostActivity : AppCompatActivity(){

  var flutterEngine //快取中拿到的FlutterEngine
  var flutterChannel // BasicMessageChannel 下面會有專門的介紹
  var flutterView 
  onCreate(){
    //在onCreate方法呼叫之初,就提前預熱FlutterEngine,可以使Widget加載更流暢
    flutterEngine.lifecycleChannel.appIsResumed()
    //同樣在onCreate中發送訊息給FluuterEngine,提前替換我們要加載的Widget,方式有過渡效果
    flutterChannel.sendMessage(routePath)
    super.onCreate()
    setContentView(flutterView = createFlutterView())
  }

  onResume(){
    super()
    flutterEngine.lifecycleChannel.appIsResumed()
  }

  onPause(){
    super()
    flutterEngine.lifecycleChannel.appIsPaused()
  }

  onDestroy(){
    super()
    flutterView.detachFromFlutterEngine()
  }
}

第三個問題,監聽FlutterEngine里Widget堆疊資訊的變化,在MaterialApp初始化的時候,有一個navigatorObservers的引數,支持我們添加navigator的變化資訊(Navigator是Flutter提供的頁面切換類),

void main() {
  //這里使用了Get框架來演示,但這不是必須的
  var getApp = GetMaterialApp(
    initialRoute: RouterMapper.ROUTER_HOME,
    getPages: [
      GetPage(
          name: RouterMapper.ROUTER_HOST, //空白的HostView
          page: () => Host(),
          transition: Transition.rightToLeft),
      ...
    ],
    navigatorObservers: [RouteNavigatorObserver()],
  );
  runApp(getApp);
  RouterHelper.registerApp(); //在這里注冊訊息監聽
}

class RouteNavigatorObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
  	// 有Widget入堆疊 可以從route中獲取name資訊并同步到Native
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    // 有Widget出堆疊 可以從route中獲取name資訊并同步到Native
  }

  @override
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    // 新的Widget替換了前一個Widget 可以從newRoute&oldRoute中獲取name資訊并同步到Native
  }

  @override
  void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
    // 一個Widget被remove了,一般不建議這么做
  }
}

通過繼承NavigatorObserver類并注冊到navigatorObservers中,我們實作了對FlutterEngine中路由資訊變化的監聽,那么接著來下一個問題,我們如何把訊息同步給Native?

**第四個問題,**Flutter提供了三種方式用來和Native互動資料,分別是BasicMessageChannel,MethodChannel和EventChannel,其中前兩個是可以雙向傳遞資料的,EventChannel只支持Native給Flutter傳遞資料,常用語系統訊息的一個通知,MethodChannel用來傳遞方法呼叫,BasicMessageChannel用來傳二進制資料,更適合我們的試用場景,接下來我們需要在Flutter和Native層住的BasicMessageChannel用來資料的互動,

那我們分別在Flutter和Native層創建BasicMessageChannel:

//Flutter
class RouterHelper {
  //注冊訊息通道
  static final _routerMessageChannel =
      BasicMessageChannel<String?>("flutter_router_channel", StringCodec());

  static registerApp() {
    //防止下面空例外
    WidgetsFlutterBinding.ensureInitialized();
    //注冊訊息監聽
    _routerMessageChannel.setMessageHandler((String? message) async {
      if (message != null) {
        //native層傳遞過來的訊息
      }
    });
  }
}
//Kotlin
fun initMessageChannel(){
  var messageChannel = BasicMessageChannel(
      engine.dartExecutor,
      "flutter_router_channel",
      StringCodec.INSTANCE)

  messageChannel.setMessageHandler{ message, reply ->
      //處理Flutter發送的訊息
  }
}

訊息的發送由BasicMessageChannel提供的send方法實作,在上面的一個問題中,我們已經通過監聽Navigator來判斷Flutter中頁面的變化資訊,接下來就要在監聽方法中,把對應的資訊發送到Native層進行處理,在Native層我們可以抽象出來一個介面,讓HostActivity實作這介面,通過面向介面編程的方式,把訊息分發到當前活躍的HostActivity中,而HostActivity中維護了一個堆疊來記錄Flutter中堆疊資訊的變化,

/**
 * flutter路由變化回呼
 */
interface RouteCallback {
		//flutter route入堆疊訊息
    fun onPush(route: String)
		//flutter route出堆疊訊息
    fun onPop(route: String)
		//flutter route堆疊替換訊息
    fun onReplace(newRoute: String, oldRoute: String)
		//flutter route被移除的訊息
    fun onRemove(route: String)
		//flutter申請打開Native頁面的訊息
    fun routeNative(nativeRoute: String, params: HashMap<String, Any>? = null)
		//flutter route出堆疊訊息
    fun getLifecycleOwner(): LifecycleOwner
}

class HostActivity : AppCompatActivity(), RouteCallback {
	  //記錄flutter的路由堆疊資訊
    private val routeStack: Stack<String> by lazy {
        Stack()
    }

    //TODO RouteCallback介面的實作方法,在方法中對routeStack進行入堆疊和出堆疊操作
}

最后一個問題,我們需要用戶進行回傳操作的時候,Widget頁面要和HostActivity保持同步,例如當前HostActivity只打開了一個Widget,那么這個Widget退出的時候,HostActivity也要同步finish掉,即使FlutterEngine中還存在其他的Widget,我們可以通過HostActivity中維護的routeStack來實作,

override fun onBackPressed() {
 		//判斷當前堆疊的長度,如果當前HostActivity堆疊的長度小于等于1,那么Activity就要finsih
    if (routeStack.size <= 1) {
      super.onBackPressed()
      flutterEngine.navigationChannel.popRoute()
    } 
    //正常執行Navigator的pop操作
    else {
      flutterEngine.navigationChannel.popRoute()
    }
}

當然還有一個問題需要注意,有些Widget的回傳并不是通過回傳鍵處理的,那我們就需對onPop方法進行一些特殊處理:

override fun onPop(route: String) {
    //正常處理出堆疊邏輯
    if (routeStack.isEmpty() && !isFinishing) {
      	//如果已經全部出堆疊,則當前HostActivity的業務已完成  
      	finish()
    }
}

這樣,就能把HostActivity和該宿主內打開的Widget進行關聯,做到共同進退,主要的邏輯實作起來也不負責,也不需要使用任何第三方的框架,這樣就有了很大的靈活性,尤其是對Flutter來說,Flutter的生態還不是十分成熟,避免使用侵入性過大的框架,也為以后技術的迭代留有足夠的空間,


缺點和不足

雖然通過對Flutter內堆疊資訊變化的監聽和通過BasicMessageChannel的訊息同步來做好混合堆疊管理,但是目前依然有一些問題需要解決,

1:Flutter和Native頁面的回傳值監聽,OneActivity打開了一個HostActivity并想要在HostActivity退出的時候給OneActivity一個回傳值,這個功能實體代碼中還沒有實作,等有空繼續完善該框架,

2:跨域回傳的問題,這個“跨域”是我自己定義的一個名字,就是如果我打開了兩個HostActivity,第二個HostActivity通過Navigator的remove方法想要關閉掉第一個HostActivity中打開的Widget,這個是可以做到了,因為這兩個HostActivity使用的是同一個FlutterEngine,如果出現這種操作,那就會讓第一個HostActivity的頁面顯示出現問題,其實我在想,理想的混合管理框架應該是把每個打開的HostActivity當做一個WebView來看待,想要在第二個WebView中關閉第一個WebView里打開的頁面,這顯然也是不太合適的,這種跨域回傳是否需要支持,也是一個值得考慮的問題,

最后

小編在網上收集了一些 Android 開發相關的學習檔案、面試題、Android 核心筆記等等檔案,希望能幫助到大家學習提升,如有需要參考的可以直接去我 CodeChina地址:https://codechina.csdn.net/u012165769/Android-T3 訪問查閱,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/287762.html

標籤:其他

上一篇:來深入了解一波鴻蒙開發

下一篇:十年沉淀,回頭發覺我當年面試 “Android” 竟然這么難!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more