跳到主要内容

mPaaS 部署

SDK 目录结构

.
├── bcpkix-jdk15to18-1.69.jar
├── bcprov-jdk15to18-1.69.jar
├── nbs.newlens.android.log-1.0.1.aar
├── nbs.newlens.nativecrash-2.0.7.aar
├── rewriter
│   ├── json-20231013.jar
│   ├── nbs.newlens.so.parser-1.2.1.jar
│   ├── tingyun-ea-agent-android-class-rewriter-2.17.4.jar
│   └── tingyun-ea-agent-android-gradle-plugin-2.17.4.jar
├── shark-1.0.2.jar
├── tingyun-android-base-1.0.2.aar
├── tingyun-basemonitor-1.0.2.aar
├── tingyun-dump-1.0.2.aar
├── tingyun-ea-agent-android-2.17.4.aar
└── tingyun-javaleak-1.0.2.aar

壳项目(portal)添加依赖

在 project 级别的 build.gradle 文件中添加以下内容。

buildscript {
dependencies {
classpath fileTree(dir: 'rewriter', include: ['*.jar'])//将 sdk 的 rewriter 文件夹解压到 project 级别的 build.gradle 文件同级目录下,rewriter 文件夹中的 jar 包仅在编译时使用,不会打包到 apk 中
}
}

allprojects {
repositories {
flatDir {
dirs 'libs'
}
}
}

在 app 级别的 build.gradle 文件中添加以下内容。

apply plugin: 'newlens'

dependencies {
// 将 sdk 复制到 portal 项目 libs 目录下
//请将「Version」更改具体版本号
implementation(name: 'tingyun-ea-agent-android-version', ext: 'aar')
implementation(name: 'nbs.newlens.nativecrash-version', ext: 'aar') // 采集 natvie crash 需集成此包
implementation(name: 'nbs.newlens.android.log-version', ext: 'aar') // 日志回捞需集成此包
// 采集 OOM 数据需要 kotlin-gradle-plugin 插件 1.3+ ,并依赖 androidx.core:core-ktx、androidx.appcompat:appcompat、androidx.lifecycle:lifecycle-process、com.squareup.okio:okio 等库
implementation(name: 'tingyun-javaleak-version.aar', ext: 'aar') // 采集OOM 需集成此包
implementation(name: 'tingyun-basemonitor-version.aar', ext: 'aar') // 采集 OOM 需集成此包
implementation(name: 'tingyun-android-base-version', ext: 'aar') // 采集OOM 需集成此包
implementation(name: 'tingyun-dump-version', ext: 'aar') // 采集 OOM 需集成此包
implementation files('libs/shark-version.jar') // 采集 OOM 需集成此包
implementation files('libs/bcpkix-jdk15to18-version.jar') // 启用国密加密需集成此包
implementation files('libs/bcprov-jdk15to18-version.jar') // 启用国密加密需集成此包
}

子项目(bundle)添加依赖

每个 bundle 都需要配置嵌码,在 project 级别的 build.gradle 文件中添加以下内容。

buildscript {
dependencies {
classpath fileTree(dir: 'rewriter', include: ['*.jar'])//将 sdk 的 rewriter 文件夹解压到 project 级别的 build.gradle 文件同级目录下,rewriter 文件夹中的 jar 包仅在编译时使用,不会打包到 apk 中
}
}

在 app 级别的 build.gradle 文件中添加以下内容。

apply plugin: 'newlens'

若插件中需要调用 SDK 中的方法,在 app 级别的 build.gradle 文件中添加以下内容。

dependencies {
// 将 tingyun-ea-agent-android-version.aar 复制到 bundle 项目 libs 目录下
compileOnly fileTree(include: ['*.aar'], dir: 'libs')
}

设置 Application

在 portal 中需使用自定义的 Application。

public class MyApp extends com.alipay.mobile.quinox.LauncherApplication {

@Override
public void onCreate() {
super.onCreate();
}
}

在 portal 的 AndroidMainfest 中配置 Application。

<application
android:name=".MyApp"
>

添加 SDK

获取 AppKey

初始化 SDK

在 Application 中的 onCreate() 方法初始化 SDK。

//"Appkey" 请从基调听云平台获取
//"Host" 为基调听云平台「Redirect」服务器地址,无需添加协议头
NBSAppAgent.setLicenseKey("AppKey").setRedirectHost("Host").startInApplication(this.getApplicationContext());

SDK 默认以 Https 上传数据,若服务端只支持 Http,需设置 「setHttpEnabled(true)」。

NBSAppAgent.setLicenseKey("AppKey").setRedirectHost("Host").setHttpEnabled(true) .startInApplication(this.getApplicationContext());

权限配置说明

SDK 为了与服务端交互「网络权限」为必要权限。

<!--必要权限,用以与服务端交互-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--非必要权限,用以获取当前设备的网络状态和WiFi状态,如:3G、4G、5G、WiFi,建议添加-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--非必要权限,用以获取 targetSdkVersion 29 及以上、 Android 10 及以上设备的网络状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--非必要权限,用以使用「可视化操作命名功能」-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
<!--非必要权限,用以获取当前移动网络连接的基站信息-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

首次启动开启模块功能开关

出于兼容性考虑, 首次启动 SDK 仅在调试模式下开启全部功能模块,非调试模式下仅开启崩溃模块,可通过以下接口开启 SDK 的模块开关。

  • 模块功能开关接口
/*
SDK首次初始化由于尚未与基调听云平台交互,默认模块开关仅开启「崩溃模块」,可以通过本接口自定义首次启动开启的模块。
@warning:调用该接口设置启动选项,SDK首次启动不受基调听云平台开关控制
*/
NBSAppAgent.setStartOption(int option);
  • 代码示例
//在SDK初始化时调用, 首次启动全部功能模块
NBSAppAgent.setLicenseKey("AppKey").setRedirectHost("Host").setStartOption(511).start(this.getApplicationContext());//首次初始化开启全部功能

网络插码

项目需实现自定义的 RpcInterceptor,并在各个方法中添加听云 NBSInterceptorHelper 的对应方法。

// mpaas rpc 只能添加一个拦截器,若项目中已存在拦截器,可以直接在拦截器的回调方法中调用 NBSInterceptorHelper 相应方法即可。
rpcService.addRpcInterceptor(OperationType.class, new CommonInterceptor());

public class CommonInterceptor implements RpcInterceptor {

private Handler handler = new Handler(Looper.getMainLooper());

@Override
public boolean preHandle(Object o, ThreadLocal<Object> threadLocal, byte[] bytes, Class<?> aClass, Method method, Object[] objects, Annotation annotation, ThreadLocal<Map<String, Object>> threadLocal1) throws RpcException {
RpcInvocationHandler rpcInvocationHandler = (RpcInvocationHandler) Proxy.getInvocationHandler(o);
RpcInvokeContext rpcInvokeContext = rpcInvocationHandler.getRpcInvokeContext();

com.networkbench.agent.impl.instrumentation.NBSInterceptorHelper.preHandle(annotation, rpcInvokeContext);
return true;
}

@Override
public boolean postHandle(Object o, ThreadLocal<Object> threadLocal, byte[] bytes, Class<?> aClass, Method method, Object[] objects, Annotation annotation) throws RpcException {
RpcInvocationHandler rpcInvocationHandler = (RpcInvocationHandler) Proxy.getInvocationHandler(o);
RpcInvokeContext rpcInvokeContext = rpcInvocationHandler.getRpcInvokeContext();

com.networkbench.agent.impl.instrumentation.NBSInterceptorHelper.postHandle(annotation, rpcInvokeContext);
return true;
}

@Override
public boolean exceptionHandle(Object o, ThreadLocal<Object> threadLocal, byte[] bytes, Class<?> aClass, Method method, Object[] objects, final RpcException e, Annotation annotation) throws RpcException {

//SDK 定义了部分网络错误码,如,未知主机901、建连失败902、连接超时903、SSL错误908等,未定义的错误码报表不会展示,您可以根据需要需对 mpaas 的错误码进行转换

int errorCode = e == null ? 0 : e.getCode();
switch (errorCode) {
case 0 :
errorCode= 900;break;
case 1 :
errorCode= 900;break;
case 2 :
errorCode= 901;break;
case 3 :
errorCode= 908;break;
case 4 :
errorCode= 903;break;
case 5 :
errorCode= 903;break;
case 6 :
errorCode= 900;break;
case 7 :
errorCode= 900;break;
case 8 :
errorCode= 900;break;
case 9 :
errorCode= 902;break;
case 10 :
errorCode= 900;break;
case 13 :
errorCode= 900;break;
case 15 :
errorCode= 902;break;
case 16 :
errorCode= 901;break;
case 18 :
errorCode= 900;break;
}

com.networkbench.agent.impl.instrumentation.NBSInterceptorHelper.exceptionHandle(annotation, errorCode);
return true;
}
}

内嵌 WebView 插码

SDK 支持对 MPNebula.startUrl() 、MPNebula.startApp() 等方法自动采集 H5 数据,无需额外配置。

若项目使用内嵌 WebView 方式,需要手动埋点。

  • 相关接口
/** 
* @param h5Page H5Page 对象
* @param apWebViewClient 若存在自定义的 APWebViewClient 实现类,传入该对象,否则传 null
* @param apWebChromeClient 若存在自定义的 APWebChromeClient 实现类,传入该对象,否则传 null
*/
NBSNebulaWebViewConfig.configWebView(H5Page h5Page, APWebViewClient apWebViewClient, APWebChromeClient apWebChromeClient);
  • 代码示例
MPNebula.getH5ViewAsync(this, param, new H5PageReadyListener() {
@Override
public void getH5Page(H5Page h5Page) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
// 不存在自定义的 APWebViewClient 或 APWebChromeClient 时,只需传入 h5Page 对象
NBSNebulaWebViewConfig.configWebView(h5Page, null, null);

mLayout.addView(h5Page.getContentView(), lp);
}
});

获取用户标识

通过添加「用户标识」可在基调听云报表平台通过该标识检索到具体用户的性能问题。

  • 相关接口
//userIdentifier 最多包含64个字符,支持中文、英文、数字、下划线,但不能包含空格或其他的转义字符
NBSAppAgent.setUserIdentifier(String userIdentifier);
  • 代码示例
public class MainActivity extends Activity {  
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String userIdentifier = getUserID();
NBSAppAgent.setLicenseKey("AppKey").withLocationServiceEnabled(true).start(this.getApplicationContext());
//用户标识可为邮箱、手机号等能够标识用户身份的信息,如:xxx@tingyun.com
NBSAppAgent.setUserIdentifier(userIdentifier);
}
}

启用国密加密

SDK 支持国密加密方式发送数据。

注意

  • 国密加密只支持 Android 6.0 及以上版本,启用国密加密后,安卓 5.x 及以下版本 SDK 将不采集数据。

  • 启用国密需集成 bcpkix-jdk15to18-version.jar 和 bcprov-jdk15to18-version.jar。

  • 服务端也需要同步开启国密加密功能。

  • 相关接口
//isEncryptionRequired 默认 false,设置为 true 启用国密加密
NBSAppAgent.encryptionRequired(boolean isEncryptionRequired)
  • 代码示例
NBSAppAgent.setLicenseKey("AppKey").setRedirectHost("Host")
.encryptionRequired(true)// 启用国密加密
.start(this.getApplicationContext());

配置混淆

在proguard混淆配置文件中增加以下内容,以免 SDK不可用。

# ProGuard configurationsfor NetworkBench Lens 
-keep class com.networkbench.** { *; }
-dontwarn com.networkbench.**
-keepattributes Exceptions, Signature, InnerClasses
# End NetworkBench Lens

若项目使用了 OkHttp 3,请在 proguard.cfg 中添加以下内容,以免影响网络指标采集。

-keep class okhttp3.** { *;}
-dontwarn okhttp3.**

若项目启用了国密,请在 proguard.cfg 中添加以下内容,以免影响数据采集。

-keep class org.bouncycastle.**{ *;}
-dontwarn org.bouncycastle.**

若需要保留行号信息,请在proguard.cfg 中添加以下内容。

-keepattributes SourceFile,LineNumberTable

打包编译

先打包子项目 bundle,再打包壳项目 portal。

嵌码验证

嵌码完成后可通过 “LogCat” 查看听云 SDK 日志输出结果,用以进行数据收集服务器校验TAG为NBSAgent,标准日志输出结果如下所示:

NBSAgent start
NBSAgent enabled
NBSAgent V “TingYun_Version” //TingYun_Version 为当前SDK的版本号
connect success

附录(可选配置)

开启可视化命名

开启可视化命名功能,可以通过在 App 应用内点选的方式为「原生页面」和「操作」进行重命名并在用户体验模块中展示。

  1. 获取 Scheme。

    在应用「设置」中的「修改设置」中选择【URL Scheme】。

  2. 在 AndroidMainfest.xml 文件的「LAUNCHER Actvitiy」中增加 scheme 配置,如下所示:

    <activity android:name=".MainActivity">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <!--请添加这里的整个intent-filter区块,并确保其中只有一个data字段-->
    <intent-filter>
    <data android:scheme="tingyun.xxxx" />
    <!--请将 scheme 中的“tingyun.xxxx”替换为基调听云报表设置页面中的 URL Scheme-->
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
    <!--请添加这里的整个intent-filter区块,并确保其中只有一个data字段-->
    </activity>