flutter SDK

更新时间:
复制为 MD 格式

Quick Tracking 统计SDK Flutter插件集成说明

集成Flutter插件

环境准备

qt_common_sdk: ^2.1.4

|---依赖原生iOS 1.7.6 版本

|---依赖原生 Android 1.8.5.PX 版本

手动集成

  • 下载本工程git库:flutter-ananlytics-plugin,删除工程目录下.git隐藏目录。

  • 将本工程根目录下android、ios、lib三个文件夹和pubspec.yaml配置文件拷贝到您的flutter工程中。

在您的flutter工程pubspec.yaml中加入插件依赖

#本地依赖

qt_common_sdk:
 path: ../

线上依赖

在工程pubspec.yaml中加入 dependencies

# 线上依赖
dependencies:
  qt_common_sdk: ^2.1.4

导入

import 'package:qt_common_sdk/qt_common_sdk.dart';

基座配置

Android端基座配置

请参考本工程中示例Android 宿主工程中App.java文件(example/android/app/src/main/java/com/aliyun/qt_common_sdk_example/App.java),给您的flutter工程Android宿主工程增加App类,注意此类必须是 io.flutter.app.FlutterApplication 类的子类。在App类的onCreate生命周期函数内,调用原生统计SDK的预初始化方法QtConfigure.preInit,并传入appkey和渠道参数。

image.png

另外,您还需要在Android宿主工程AndroidManifest.xml清单文件中 application 配置中添加 “android:name”属性,其值为新增的 App 类。如下图:

image.png

注意,预初始化传入的appkey和渠道参数必须和后续在flutter工程的dart代码中调用的SDK正式初始化函数QTCommonSdk.initCommon 传入的第一个参数(Android appkey)和第三个参数(Android 渠道)必须严格一致。

为了满足《隐私政策》要求,开发者必须保证在应用安装后,首次冷启动场景,只能在App用户同意隐私授权之后,才能调用flutter插件的QTCommonSdk.initCommon接口真正出初始化SDK。

用户已经同意隐私授权之后的后续应用冷启动,可以在flutter首个页面初始化时直接调用QTCommonSdk.initCommon接口初始化SDK。

混淆配置

Flutter Build APK默认会开启R8如果您的应用使用了代码混淆,请添加如下配置,以避免Quick Tracking SDK被错误混淆导致SDK不可用。

-keep class com.quick.qt.** {*;}
-keep class rpk.quick.qt.** {*;}
-dontwarn com.quick.qt.analytics.middle.DevLog

-keepclassmembers class * {
   public <init> (org.json.JSONObject);
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

SDK需要引用导入工程的资源文件,通过了反射机制得到资源引用文件R.java,但是在开发者通过proguard等混淆/优化工具处理apk时,proguard可能会将R.java删除,如果遇到这个问题,请添加如下配置:

-keep public class [您的应用包名].R$*{
public static final int *;
} 

隐私政策合规以及Flutter插件正式初始化

1.合规声明

您务必告知用户您选择SDK服务,请在《隐私政策》中增加如下参考条款:

“我们的产品集成SDK,SDK需要收集您的设备识别码(IDFA/IDFV/OPENUDID/GUID/)以提供统计分析服务,并通过地理位置校准报表数据准确性,提供基础反作弊能力。”

2.合规初始化

为保证您的App在集成统计SDK之后,能够满足工信部相关合规要求,您应确保App首次冷启动时,在用户阅读您的《隐私政策》并取得用户授权之后,才能调用flutter插件的QTCommonSdk.initCommon接口真正出初始化SDK,此时SDK才会真正采集设备信息并上报数据。反之,如果用户不同意《隐私政策》授权,则不能调用初始化函数。

一旦App获取到《隐私政策》的用户授权,后续的App冷启动,开发者应该保证调用到初始化函数。

3. 初始化代码示例

if (!sdkHasInit) {
      sdkHasInit = true;

      // 区分 iOS 和 Android 平台
      if (Platform.isAndroid) {
        // Android 平台特定代码
        QTCommonSdk.setCustomDomain(DOMAIN, DOMAIN);
        QTCommonSdk.setLogEnabled(true);
        QTCommonSdk.initCommon(APP_ANDROID_KEY, APP_IOS_KEY, 'Android 应用市场');
      } else if (Platform.isIOS) {
        // iOS 平台特定代码
        QTCommonSdk.setCustomDomain(DOMAIN, DOMAIN);
        QTCommonSdk.setLogEnabled(true);
        QTCommonSdk.initCommon(APP_ANDROID_KEY, APP_IOS_KEY, 'App Store');
      }
    }
    ...

插件接口说明

如下各个接口注释部分会针对接口或者参数标注 "Android特有" 或 "iOS特有",请注意区分。 没有特别标注的接口或者参数即为AndroidiOS双端通用。

///
  /// 设置上报统计日志的主域名和备用域名。此函数必须在SDK初始化函数调用之前调用。
  ///
  /// @param primaryDomain String 主域名.
  /// @param standbyDomain String 备用域名 上传日志备用域名收数地址,参数可以为null或者空串,若此参数为空,SDK内部会自动将主域名设置为备用域名。
  ///
  ///
  static void setCustomDomain(String primaryDomain, String standbyDomain)

  ///
  /// 初始化
  ///
  /// @param androidAppkey String 开发者申请的android appkey.
  /// @param iosAppkey String 开发者申请的ios appkey.
  /// @param channel String 渠道标识,可设置nil表示"App Store".
  ///
  ///
  static Future<dynamic> initCommon(
      String androidAppkey, String iosAppkey, String channel)
      
  ///
  /// 自定义app版本号,默认获取version,只可设置一次建议在所有接口之前调用
  ///
  /// @param appVersion String 自定义版本号
  /// @param appVersionCode int 对应Android应用版本号versionCode,仅Android端会使用此参数
  ///
  static void setAppVersion(String appVersion, int appVersionCode)

  ///
  /// 设置是否在console输出sdk的log信息.
  ///
  /// @param bFlag bool 默认NO(不输出log); 设置为YES, 输出可供调试参考的log信息. 发布产品时必须设置为NO.
  ///
  ///
  static void setLogEnabled(bool bFlag)

  ///
  /// 自定义事件
  ///
  /// @param event String 事件Id.
  /// @param properties Map 自定义参数.
  ///
  static void onEvent(String event, Map<String, dynamic> properties) 

  ///
  /// dart全埋点点击事件通道

  ///
  /// 自定义事件
  ///
  /// @param event String 事件Id.
  /// @param pageName String 页面名称.
  /// @param properties Map 自定义参数.
  ///
  static void onEventWithPage(
      String event, String pageName, Map<String, dynamic> properties) 

  ///
  /// 账号统计登录
  ///
  /// @param userID String user's ID
  ///
  ///
  static void onProfileSignIn(String userID) 

  ///
  /// 账号统计登录
  ///
  /// @param userID String user's ID
  /// @param provider String user's provider
  ///
  static void onProfileSignInEx(String userID, String provider) 

  ///
  /// 账号统计登出
  ///
  ///
  static void onProfileSignOff() 

  ///
  /// 页面统计
  ///
  /// @param viewName String 页面名称
  ///
  ///
  static void onPageStart(String viewName) 

  ///
  /// 页面统计
  ///
  /// @param viewName String 页面名称
  ///
  ///
  static void onPageEnd(String viewName) 

  ///
  /// 注册全局属性
  ///
  /// @param properties Map 自定义参数
  ///
  ///
  static void registerGlobalProperties(Map<String, dynamic> properties) 
  
  ///
  /// 删除一个全局属性
  ///
  /// @param propertyName String 自定义参数key
  ///
  ///
  static void unregisterGlobalProperty(String propertyName) 

  ///
  /// 获取全局属性
  ///
  ///
  static Future<String>? get getGlobalProperties async 

  ///
  /// 获取一个全局属性值
  ///
  ///
  static Future<dynamic>? getGlobalProperty(String propertyName) async
  
  ///
  /// 清除全局属性
  ///
  static void clearGlobalProperties() 

  ///
  /// 跳过当前页面统计.
  ///
  /// @param pageName String 页面名称
  ///
  ///
  static void skipMe(String pageName)
  
  ///
  /// 设置页面属性.
  ///
  /// @param pageName String 页面名称
  /// @param properties Map 自定义参数
  ///
  static void setPageProperty(
      String pageName, Map<String, dynamic> properties)

  ///
  /// 更新当前的spm
  ///
  /// @param curSPM String 当前页面事件的spm
  ///
  static void updateCurSpm(String curSPM) 

  ///
  /// 更新下一个页面业务参数
  ///
  /// @param properties Map 传给下一个页面业务参数,kv对
  ///
  static void updateNextPageProperties(Map<String, dynamic> properties) 

  ///
  /// 自定义设备id
  ///
  /// @param customDeviceId String
  ///
  static void setCustomDeviceId(String customDeviceId) 

  ///
  /// 获取设备id
  ///
  ///
  static Future<dynamic>? getDeviceId() async 

  ///
  ///  ios 专有API
  /// 是否hook系统方法
  ///
  /// @param value bool
  ///
  ///
  static void isHook(bool value) 
  static void isHookUrl(bool value) 
  static void isHookEvent(bool value) 
  static void isHookPage(bool value) 

  ///
  /// ios 专有API
  /// 自定义 openudid 设置
  ///
  /// @param customOpenUdid 自定义的 openudid
  ///
  ///
  static void setCustomOpenUdid(String customOpenUdid) 

  ///
  /// ios 专有API
  /// 自定义 idfa 设置
  ///
  /// @param customIdfa 自定义 idfa
  ///
  ///
  static void setCustomIdfa(String customIdfa) 

  ///
  /// ios 专有API
  /// 自定义 idfv 设置
  ///
  /// @param customIdfv 自定义 idfv
  ///
  ///
  static void setCustomIdfv(String customIdfv) 

  ///
  /// ios 专有API
  /// 自定义 utdid 设置
  ///
  /// @param customUtdid 自定义 utdid
  ///
  ///
  static void setCustomUtdid(String customUtdid) 
  
  ///
  /// ios 专有API
  /// 自定义 mcc 设置
  ///
  /// @param customMcc 自定义 mcc
  ///
  ///
  static void setCustomMcc(String customMcc) 

  ///
  /// ios 专有API
  /// 自定义 mnc 设置
  ///
  /// @param customMnc 自定义 mnc
  ///
  ///
  static void setCustomMnc(String customMnc) 

  ///
  /// ios 专有API
  /// 自定义 localIP 设置
  ///
  /// @param customLocalIP 自定义 localIP
  ///
  ///
  static void setCustomLocalIP(String customLocalIP) 

  ///
  /// 应用如果以强杀死自身进程方式暴力退出,
  /// 则需要在自杀前调用此接口,Android特有
  ///
  ///
  static void onKillProcess() 

  //
  // QT JS SDK通过flutter_webview_plugin插件将JS层统计数据发送到flutter层JavascriptChannel接口
  // 时需调用此接口,具体示例代码见example/lib/main.dart 第15行~第23行 写法。
  //
  static void onJSCall(String msg) 

  static void setViewProperties(String keyName, dynamic value) 
  
  ///
  /// 自动埋点专用
  /// event 事件遍码
  /// autoTrackProperties 预制参数
  /// customProperties 自定义参数
  static void onAutoEvent(
      String event,
      Map<String, dynamic> autoTrackProperties,
      Map<String, dynamic>? customProperties) 

flutter_webview_plugin插件配合QT JS SDK桥接使用说明

flutter工程使用社区flutter_webview_plugin(支持版本0.4.0+) + H5做混合开发时,如果在H5页面中集成了QuickTracking JS版本统计SDK,则通过使用onJSCall接口API,支持将QT JS SDK的统计数据透传至 Android/iOS原生统计SDK,由原生统计SDK上报JS SDK统计数据。

开发者需要参考示例工程example/lib/main.dart 第15行~第23行 写法。给flutter_webview_plugin插件注册一个名为'Umeng4AplusFlutter'的JS bridge通过,然后在onMessageReceived: (JavascriptMessage message)回调函数中调用QTCommonSdk.onJSCall(message.message);

如下示例代码可以在example/lib/main.dart文件中找到。

// 定义一个名为'Umeng4AplusFlutter'的JS bridge通道回调对象
final Set<JavascriptChannel> jsChannels = [
   JavascriptChannel(
       name: 'Umeng4AplusFlutter',
       onMessageReceived: (JavascriptMessage message) {
         // print(message.message);
         QTCommonSdk.onJSCall(message.message);
       }),
].toSet();

//..........

// 开启flutter webview 插件对象时将js bridge对象注册上
flutterWebViewPlugin.launch(
                   selectedUrl,
                   javascriptChannels: jsChannels,
                   rect: Rect.fromLTWH(
                        0.0, 0.0, MediaQuery.of(context).size.width, 300.0),
                   userAgent: kAndroidUserAgent,
                   invalidUrlRegex:
                        r'^(https).+(twitter)', // prevent redirecting to twitter when user click on its icon in flutter website
								 );

注意: 需要先调用 QTConfigure.init 来初始化插件(Appkey可在统计后台 “管理->应用管理->应用列表” 页面查看,或在 “我的产品”选择某应用->设置->应用信息 查看Appkey),才能保证其他功能正常工作。