主頁 > 移動端開發 > Flutter例外監控 - 叁 | 從bugsnag原始碼學習如何追溯例外產生路徑

Flutter例外監控 - 叁 | 從bugsnag原始碼學習如何追溯例外產生路徑

2023-01-07 07:32:29 移動端開發

如果覺得文章對你有幫助,點贊、收藏、關注、評論,一鍵四連支持,你的支持就是我創作最大的動力,

?? 本文原創聽蟬 公眾號:碼里特別有禪 歡迎關注原創技術文章第一時間推送  ??

前言

沒錯,繼Flutter 例外監控 | 框架 Catcher 原理分析 之后,帶著那顆騷動的好奇心我又搗鼓著想找其他 Flutter 例外監控框架讀讀,看能不能找到一些好玩的東西,于是在官方介紹第三方庫里發現了這貨Bugsnag,大致掃了下原始碼發現 flutter 側主流程很簡單沒啥東西可看滴,因為這貨強烈依賴對端能力,Flutter 例外捕獲之后就無腦拋給對端 SDK 自己啥都不干 ,拋開 Bugsnag 這種處理例外的方式不論,原始碼里卻也有一些之我見的亮度值得借鑒和學習,比如本文主要介紹 Bugsnag 如何追溯例外路徑的設計思想和實作,對例外捕獲的認識有不少幫助,

Bugsnag

功能簡介

在介紹可追溯例外路徑設計之前,有必要先科普下 Bugsnag 是什么? 讓大佬們有一個大局觀,畢竟后面介紹內容只是其中一個小的點,

Bugsnag 跟 Catcher 一樣也是 Flutter 例外監控框架,Bugsnag-flutter 只是殼,主要作用有:

  1. 規范多平臺(安卓,ios)例外呼叫和上報的介面,
  2. 拿到 flutter 例外相關資料傳遞給對端,

主要支持功能:

  1. dart 側例外支持手動和自動上報,
  2. 支持上報資料序列化,有網環境下會繼續上報,
  3. 支持記錄用戶導航步驟,自定義關鍵節點操作,網路例外自動上報,

這個框架的側重點跟 Catcher 完全不同,它不支持例外的 UI 客戶端自定義顯示,也不支持對例外的定制化處理,說白了就是你想看例外就只能登陸到Bugsnag 后臺看到,后臺有套餐包括試用版和收費版(你懂滴),

基本使用

void main() async => bugsnag.start(
      runApp: () => runApp(const ExampleApp()),
      // 需要到bugsang后臺注冊賬號申請一個api_key
      apiKey: 'add_your_api_key_here',
      projectPackages: const BugsnagProjectPackages.only({'bugsnag_example'}),
      // one rror callbacks can be used to modify or reject certain events
      //...
    );

class ExampleApp extends StatelessWidget {
  const ExampleApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [BugsnagNavigatorObserver()],
      initialRoute: '/',
      routes: {
        '/': (context) => const ExampleHomeScreen(),
        '/native-crashes': (context) => const NativeCrashesScreen(),
      },
    );
  }
}
// Use leaveBreadcrumb() to log potentially useful events in order to
  // understand what happened in your app before each error.
  void _leaveBreadcrumb() async =>
      bugsnag.leaveBreadcrumb('This is a custom breadcrumb',
          // Additional data can be attached to breadcrumbs as metadata
          metadata: {'from': 'a', 'to': 'z'});
import 'package:bugsnag_breadcrumbs_http/bugsnag_breadcrumbs_http.dart' as http;
void _networkFailure() async =>
      http.post(Uri.parse('https://example.com/invalid'));

后臺效果展示

Untitled.png
Flutter 例外顯示頁

Untitled 1.png
bugsnag 后臺 Breadcrumbs 頁顯示內容:可以看到路徑中包含了當前頁面資訊,請求資訊和關鍵步驟,例外生成的路徑和時間點

例外捕獲框架閱讀通用套路

在例外上報主流程之前,必要的通用套路不能忘,按照這個思路來追原始碼事半功倍,如下:

  1. Flutter 例外監控點

三把斧:FlutterError.onError ,addErrorListener,runZonedGuarded 詳見:不得不知道的 Flutter 例外捕獲知識點:Zone 中 Zone 例外捕獲小節,

  1. 針對 Error 的包裝類生成

我們最好不要直接使用 one rror 引數中的 error 和 stack 欄位,因為為方便問定位一般原始 Error 會經過各種轉換增加附加資訊更容易還原例外現場,比如設備 id 等,對比 Catcher 中這個經過包裝的物件叫Report

  1. 操作包裝類

上面最終生成的包裝類物件會經過一些操作,操作主要三個方面:顯示、存盤、上報,拿 Catcher 來舉例子,它包含了 UI 顯示和上報兩個,一般在專案中可能顯示不那么重要,最重要的是存盤和上報,

Bugsnag 主要流程原始碼簡析

主要領略下”例外捕獲通用套路” 大法有多香:

找監控點

這個流程中少了 addErrorListener,說明 bugsnag 對 isolate 例外是監控不到滴,

Future<void> start({
    FutureOr<void> Function()? runApp,
    //... Tag1 一堆額外引數
  }) async {
    //...
    //開始就想著用對端SDK,這里當然少不了初始化通道
    _runWithErrorDetection(
      detectDartErrors,
      () => WidgetsFlutterBinding.ensureInitialized(),
    );

    //...

    await ChannelClient._channel.invokeMethod('start', <String, dynamic>{
      //... Tag2:這里將Tag1處的額外引數傳給了對端SDK

    });

   //Tag3:dart error的處理類,其中全部都是通過channel來橋接的
    final client = ChannelClient(detectDartErrors);
    client._onErrorCallbacks.addAll(onError);
    this.client = client;


    _runWithErrorDetection(detectDartErrors, () => runApp?.call());
  }

  void _runWithErrorDetection(
    bool errorDetectionEnabled,
    FutureOr<void> Function() block,
  ) async {
    if (errorDetectionEnabled) {
      //多么熟悉的味道,
      await runZonedGuarded(() async {
        await block();
      }, _reportZonedError);
    } else {
      await block();
    }
  }

//最終_reportZonedError會執行到_notifyInternal
void _notifyUnhandled(dynamic error, StackTrace? stackTrace) {
    _notifyInternal(error, true, null, stackTrace, null);
  }
ChannelClient(bool autoDetectErrors) {
    if (autoDetectErrors) {
      FlutterError.onError = _onFlutterError;
    }
  }

void _onFlutterError(FlutterErrorDetails details) {
    _notifyInternal(details.exception, true, details, details.stack, null);
    //...
  }

找包裝類生成

Future<void> _notifyInternal(
    dynamic error,
    bool unhandled,
    FlutterErrorDetails? details,
    StackTrace? stackTrace,
    BugsnagOnErrorCallback? callback,
  ) async {
    final errorPayload =
        BugsnagErrorFactory.instance.createError(error, stackTrace);
    final event = await _createEvent(
      errorPayload,
      details: details,
      unhandled: unhandled,
      deliver: _onErrorCallbacks.isEmpty && callback == null,
    );

   //...

    await _deliverEvent(event);
  }

//我說什么來著:連最基本的Event構造,都是在對端,
Future<BugsnagEvent?> _createEvent(
    BugsnagError error, {
    FlutterErrorDetails? details,
    required bool unhandled,
    required bool deliver,
  }) async {
    final buildID = error.stacktrace.first.codeIdentifier;
    //...
    };
    //呼叫了對端通道方法來實作,
    final eventJson = await _channel.invokeMethod(
      'createEvent',
      {
        'error': error,
        'flutterMetadata': metadata,
        'unhandled': unhandled,
        'deliver': deliver
      },
    );

    if (eventJson != null) {
      return BugsnagEvent.fromJson(eventJson);
    }

    return null;
  }

操作包裝類

本來以為此處要大干一場,結果灰溜溜給了對端,,,,什么都不想說,內心平靜毫無波瀾~~~

Future<void> _deliverEvent(BugsnagEvent event) =>
      _channel.invokeMethod('deliverEvent', event);

主要原始碼流程看完了,下面來看下 Bugsnag 我覺得比較好玩的需求和實作,

什么是可追溯例外路徑

這個是我自己想的一個詞,該需求目的是能完整記錄用戶操作的整個行為路徑,這樣達到清晰指導用戶操作程序,對問題的定位很有幫助,可以理解成一個小型的埋點系統,只是該埋點系統只是針對例外來做的,

如下:例外產生流程,state 被成功加載后用戶先進入了主頁,然后從主頁進入了 native-crashes 頁之后例外就產生了, 對開發者和測驗人員來說很容易復現通過如上路徑來復現問題,

Untitled 2.png例外路徑后臺顯示效果

如何實作

前置知識

Bugsnag 中將可追溯的路徑命名為 Breadcrumb,剛開始我不理解,這個單詞英文意思:面包屑,跟路徑八竿子都扯不上關系,直到查維基百科才發現為什么這么命名,通過一片一片的面包屑才能找到回家的路,,,,老外們還真夠有情懷的!

Breadcrumb 的命名的含義, 有沒有發覺這個名字起得好形象!

頁面路徑(英語:breadcrumb 或 breadcrumb trail/navigation),又稱面包屑導航,是在用戶界面中的一種導航輔助,它是用戶一個在程式或檔案中確定和轉移他們位置的一種方法,面包屑這個詞來自糖果屋 這個童話故事;故事中,漢賽爾與葛麗特企圖依靠灑下的面包屑找到回家的路,

當然最終這些丟下的面包屑(leaveBreadcrumb)路徑資料也是通過呼叫到對端 SDK 來實作:

Future<void> leaveBreadcrumb(
    String message, {
    Map<String, Object>? metadata,
    BugsnagBreadcrumbType type = BugsnagBreadcrumbType.manual,
  }) async {
    final crumb = BugsnagBreadcrumb(message, type: type, metadata: metadata);
    await _channel.invokeMethod('leaveBreadcrumb', crumb);
  }

這里主要關注下自動添加面包屑的場景,

如何添加路徑

兩種方式:

  1. 手動添加,通過呼叫 bugsnag.leaveBreadcrumb

  2. 自動添加,其中包括兩個場景:導航欄跳轉和 網路請求

如上兩個場景的的實作原理涉及到對應用性能的監控功能,重點分析其中原理,

導航欄自動埋點實作原理

MaterialApp: navigatorObservers 來實作對頁面跳轉的監聽,Bugsnag 中是通過自定義 BugsnagNavigatorObserver,并在其回呼函式中監聽導航行為手動呼叫 leaveBreadcrumb 方法上報導航資訊給后臺從而達到監聽頁面的效果,

注意事項:
navigatorObservers 是創建導航器的觀察者串列,將要觀察頁面跳轉物件放在該串列中,頁面中發生導航行為時候,就可以監聽到,

如果一個應用中有多個 MaterialApp 的情況,需要保證每個 MaterialApp:navigatorObservers 中都有 BugsnagNavigatorObserver 才行,不然某些 MaterialApp 中也監控不到,最好是一個應用統一一份 MaterialApp 減少這種不必要的麻煩,

如下代碼中

  1. Bugsnag 框架自定義了 BugsnagNavigatorObserver 物件, 該物件必須繼承 NavigatorObserver 并實作其中回呼函式方可放入到 MaterialApp:navigatorObservers 中,不是隨便什么物件都可以放到串列中的,
  2. 這樣 Bugsnag 就具有了對整個接入應用導航的監控能力,頁面進入或者頁面退出行為都可以被監控到,
  3. 然后在步驟 2 回呼中手動呼叫_leaveBreadcrumb 來實作對導航路徑的監聽,
  4. _leaveBreadcrumb 將資料傳送給對端 SDK,SDK 傳輸資料給 bugsnag 后臺 Breadcrumb 頁,也就是上面效果中呈現的,
class ExampleApp extends StatelessWidget {
  const ExampleApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [BugsnagNavigatorObserver()],
      //...
    );
  }
}

----[BugsnagNavigatorObserver]----->
// BugsnagNavigatorObserver extends NavigatorObserver
BugsnagNavigatorObserver({
    //...
  }) : _navigatorName = (navigatorName != null) ? navigatorName : 'navigator';

  @override
  void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
    _leaveBreadcrumb('Route replaced on', {
      if (oldRoute != null) 'oldRoute': _routeMetadata(oldRoute),
      if (newRoute != null) 'newRoute': _routeMetadata(newRoute),
    });
    //...
  }

  //....其他回呼函式

  void _leaveBreadcrumb(String function, Map<String, Object> metadata) {
    if (leaveBreadcrumbs) {
      bugsnag.leaveBreadcrumb(
        _operationDescription(function),
        type: BugsnagBreadcrumbType.navigation,
        metadata: metadata,
      );
    }
  }

網路請求自動埋點實作原理

通過自定義 http.BaseClient 實作對默認 http.Client 中 send 方法代理來實作,對請求發送和失敗進行統一化監聽,并記錄了請求時長埋點上報,

推薦個網路監聽通用方案:
可以看下 didi 的 Flutter 方案: 復寫 HttpOverride 即可,DoKit/dokit_http.dart at master · didi/DoKit

如下

  1. 當點擊發送網路請求時,會呼叫 Bugsnag 自己的 http 庫,
  2. Bugsnag http 庫中自己實作了 Client 類,該類復寫 send 方法(該方法在發生網路行為時都會被觸發),并在其中做了網路監聽的額外埋點操作_requestFinished,其中包括對網路結果反饋和網路請求時間的統計,
  3. 例子中最終 post 會執行 client.send,從而完成了對網路自埋點路徑的上報,

Untitled 3.png

import 'package:bugsnag_breadcrumbs_http/bugsnag_breadcrumbs_http.dart' as http;
void _networkFailure() async =>
      http.post(Uri.parse('https://example.com/invalid'));

----[bugsnag_breadcrumbs_http.dart]---->
Future<http.Response> post(Uri url,
        {Map<String, String>? headers, Object? body, Encoding? encoding}) =>
    _withClient((client) =>
        client.post(url, headers: headers, body: body, encoding: encoding));

Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
  var client = Client();
  try {
    return await fn(client);
  } finally {
    client.close();
  }
}

---->[client.dart]---->
class Client extends http.BaseClient {
  /// The wrapped client.
  final http.Client _inner;

  Client() : _inner = http.Client();

  Client.withClient(http.Client client) : _inner = client;

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) async {
    final stopwatch = Stopwatch()..start();
    try {
      final response = await _inner.send(request);
      //攔截點:這里監聽發送成功
      await _requestFinished(request, stopwatch, response);
      return response;
    } catch (e) {
      //攔截點:這里監聽發送失敗
      await _requestFinished(request, stopwatch);
      rethrow;
    }
  }

  Future<void> _requestFinished(
    http.BaseRequest request,
    Stopwatch stopwatch, [
    http.StreamedResponse? response,
  ]) =>
      _leaveBreadcrumb(Breadcrumb.build(_inner, request, stopwatch, response));
}

總結

本文主要對可追溯 Crash 路徑自動埋點原理進行分析,該需求是讀 Bugsnag 是覺得想法上有亮點的地方,就重點拎出來說說,結合自身做 Flutter 例外捕獲程序經驗,壓根沒考慮到這種記錄例外路徑的需求,而且它還做得這么細針對了導航監聽和網路監聽自動埋點,而這兩塊又恰恰是對定位問題比較關鍵的,試問哪個例外出現了你不關注發生的頁面,哪個線上 App 逃得開網路例外,

另外本文也總結閱讀 Flutter 例外監控框架必看的幾個關鍵步驟,結合 Bugsnag 原始碼進行實際講解,其實 Flutter 例外監控框架來回就那么幾個步驟沒什么大的變化,主要是看其中有什么亮度的需求并針對需求做了哪些開閉設計,這些才是令人振奮的東西,

參考鏈接

bugsnag/bugsnag-flutter: Bugsnag crash reporting for Flutter apps
DoKit/Flutter at master · didi/DoKit

如果覺得文章對你有幫助,點贊、收藏、關注、評論,一鍵四連支持,你的支持就是我創作最大的動力,

?? 本文原創聽蟬 公眾號:碼里特別有禪 歡迎關注原創技術文章第一時間推送 ??

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

標籤:其他

上一篇:Web應用怎樣獲取Access Token?

下一篇:安卓+n2n實作異地組建局域網

標籤雲
其他(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