Android SDK
SDK接入流程
步骤 | 集成内容 | 本文中的位置 | 是否必选 | 附加说明 |
第一步 | 引入SDK | 查看文档「第一步引入SDK」 | 必选 | |
第二步 | 配置权限 | 查看文档 [第二步配置权限」 | 必选 | |
第三步 | 混淆配置 | 查看文档 [第三步混淆配置」 | 必选 | |
第四步 | 域名设置 | 查看文档 [第四步域名配置」 | 必选 | |
第五步 | 用户账号统计 | 查看文档 [第五步设置用户标识」 | 可选 | 自定义用户ID,设置后在产品后台会同展示用户账号 |
第六步 | 初始化 | 查看文档 [第六步初始化」 | 必选 | |
第七步 | 日志打印 | 查看文档「第七步日志打印」 | 必选 | |
第八步 | 功能模块配置 | 查看文档「第八步功能模块配置」-> 8.1崩溃分析 | 必选 | 集成且开关未关闭后自动采集,无需额外配置 |
查看文档「第八步功能模块配置」-> 8.2 自定义异常接口 | 必选 | 上报自定义类型的崩溃上报 | ||
查看文档「第八步功能模块配置」-> 8.3 卡顿分析 | 必选 | 集成开关未关闭,默认提供,如不需要卡顿分析则需要关闭此功能开关 | ||
查看文档「第八步功能模块配置」-> 8.4 网络分析 | 必选 | |||
查看文档「第八步功能模块配置」-> 8.5 启动分析 | 必选 | |||
查看文档「第八步功能模块配置」-> 8.6 内存分析 | 必选 | |||
查看文档「第八步功能模块配置」-> 8.7 APP 打通H5 | 必选 | H5页面分析 APP端需要做的打通操作说明 | ||
查看文档「第八步功能模块配置」-> 8.8 原生页面 | 必选 | |||
查看文档「第八步功能模块配置」-> 8.9 采集开关 | 必选 | 可关闭崩溃分析、启动分析、网络分析 、内存分析、应用内H5页面分析;不配置默认为开启 | ||
查看文档「第八步功能模块配置」-> 8.10 符号表 | 必选 | 崩溃问题需要上传符号表才能进行堆栈解析,本文档描述如何获取符号表并上传 | ||
附件 | DEMO | |||
附录 | SDK上报策略 |
第一步引入SDK
1.Maven地址配置
在工程 build.gradle 配置脚本中 buildscript 和 allprojects 段中添加 sdk maven 仓库地址
buildscript {
repositories {
google()
jcenter()
maven { url 'https://repo1.maven.org/maven2/' }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'}
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
maven { url 'https://repo1.maven.org/maven2/' }
}
}
2.组件引用
在工程App对应build.gradle配置脚本dependencies段中添加组件库依赖
dependencies {
implementation fileTree(include:['*.jar'], dir:'libs')
implementation 'com.umeng.umsdk:qt-common:+'
//如果您只使用UAPM产品请忽略该组件库
implementation 'com.umeng.umsdk:qt-spm:+'
//apm稳定性SDK库
implementation 'com.umeng.umsdk:apm-crash:1.5.2.1.0.0.3'
//apm性能SDK库
implementation 'com.umeng.umsdk:apm-efs:1.6.0.001.200'
}
第二步配置权限
统计SDK需要宿主APP授予如下权限:
权限 | 用途 |
ACCESS_NETWORK_STATE | 检测联网方式,在网络异常状态下避免数据发送,节省流量和电量。 |
ACCESS_WIFI_STATE | 获取WIFI mac地址,在平板设备或电视盒子上,无法通过IMEI标识设备,我们会将WIFI mac地址作为用户的唯一标识,以便正常提供统计分析服务。 |
INTERNET | 允许应用程序联网和发送统计数据的权限,以便提供统计分析服务。 |
READ_PHONE_STATE(可选) | 获取用户设备的IMEI,通过IMEI对用户进行唯一标识,以便提供统计分析服务。 |
下面给出AndroidManifest.xml清单文件示例:
<manifest ……>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application ……>
第三步混淆配置
如果您的应用使用了代码混淆,请添加如下配置,以避免 SDK被错误混淆导致SDK不可用。
-keep class com.umeng.** {*;}
-keep class com.uc.** { *; }
-keep class com.efs.** { *; }
-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 *;
}
第四步域名设置
在预初始化之前,开发者需要在调用SDK任意其它接口之前最先调用UMConfigure.setCustomDomain()接口设置私有化环境收数域名。
/**
* 设置上传统计日志的主域名和备用域名。此函数必须在SDK预初始化/初始化函数调用之前调用。SDK会优先将统计数据上报到主域名,失败的情况下会再尝试将数据上报到备用域名。
* 主域名primaryDomain或不能传入null或者空串,如果传入null或者空串,SDK预初始化函数会抛出SdkDomainUndefined运行时异常。
* @param standbyDomain 备用域名可以传入null或者空串,此时SDK认为备用域名和主域名完全相同。SDK上传数据失败后第二次也会向主域名上报数据。
* 传入的域名参数应该包含"https://" 前缀。
*/
public static void setCustomDomain(String primaryDomain, String standbyDomain)
参数 | 含义 |
primaryDomain | 上传日志的主域名收数地址。 |
standbyDomain | 上传日志备用域名收数地址。 |
APM稳定性库相关域名接口:
public static void setCustomDomainCrash(String url)
参数 | 含义 |
url | 上传日志的域名收数地址。 |
APM性能库相关域名接口:
public static void setCustomDomainCrash(String url)
参数 | 含义 |
url | 上传日志的域名收数地址。 |
示例:
public class UmengApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
UMConfigure.setCustomDomain("xxxxxx", null); // 请传入您自己的收数域名
UMEfs.setCustomDomainEfs("xxxxxx");// 请传入您自己的性能库的收数域名
UMCrash.setCustomDomainCrash("xxxxxx");// 请传入您自己的稳定性库的收数域名
// 打开调试log
UMConfigure.setLogEnabled(true);
UMConfigure.preInit(this, "xxxxxx", "Umeng");// 请传入您自己的appkey
MobclickAgent.disableActivityPageCollection();
// ...
第五步用户账号统计
可选功能,与统计分析使用同一套接口,设置后在产品后台会同展示用户账号
1、默认在统计用户时以设备为标准,如果需要统计应用自身的账号,请使用以下接口:
public static void onProfileSignIn(String ID);
public static void onProfileSignIn(String Provider, String ID);
参数 | 含义 |
ID | 用户账号ID,长度小于64字节 |
Provider | 账号来源。如果用户通过第三方账号登录,可以调用此接口进行统计。支持自定义, 不能以下划线"_"开头,使用大写字母和数字标识,长度小于32 字节; 如果是上市公司,建议使用股票代码。 |
2、账号登出时需调用此接口,调用之后不再发送账号相关内容。
public static void onProfileSignOff();
第六步初始化
6.1 初始化接口
由于工信部的合规要求App在用户同意隐私政策前不可以获取任何个人信息,所以初始化为以下操作:
1.预初始化
请在宿主App的Application.onCreate函数中调用基础组件库初始化函数。
// SDK预初始化函数不会采集设备信息,也不会向友盟后台上报数据。
// preInit预初始化函数耗时极少,不会影响App首次冷启动用户体验
UMConfigure.preInit(this,"5e3f5cae6emp7x1i4yurbd8u","Channel");
2.初始化
请务必在用户同意隐私政策后,再初始化SDK。
// 正式初始化SDK,务必调用
UMConfigure.init(this,"5e3f5cae6emp7x1i4yurbd8u",UMConfigure.DEVICE_TYPE_PHONE, "");
6.2 Appkey获取
在产品的“管理控制台”——》“应用管理”中,找到您的应用获取。
第七步日志打印
可通过UMConfigure.setLogEnabled(boolean)接口控制LOG的输出。
注意:
App正式上线前请关闭SDK运行调试日志。避免无关Log输出。
7.1 日志开关
可以通过调用如下方法控制SDK运行调试日志是否输出,默认情况下SDK运行调试日志关闭。需要用户手动打开。
/**
* 设置组件化的Log开关
* 参数: boolean 默认为false,如需查看LOG设置为true
*/
UMConfigure.setLogEnabled(true);
注意:
如果查看初始化过程中的LOG,一定要在调用初始化方法前将LOG开关打开。
7.2 日志等级
日志分为四种等级,方便用户查看:
Error(打印SDK集成或运行时错误信息)。
Warn(打印SDK警告信息)。
Info(打印SDK提示信息)。
Debug(打印SDK调试信息)。
第八步功能模块配置
8.1 崩溃分析
通用崩溃
如您完成common和apm插件的接入,即可使用Java、Native崩溃分析、ANR分析功能,无需额外其他接入操作。
如果您使用我们的SDK捕获native崩溃后,其他捕获工具无法捕获到native 崩溃,可以使用如下方法在初始化SDK后进行设置,使其他SDK可以捕获到native 崩溃
final Bundle customInfo = newBundle();
customInfo.putBoolean("mCallNativeDefaultHandler",true);
CrashApi.getInstance().updateCustomInfo(customInfo);
崩溃回调(自定义字段)
当崩溃发生时,您可以在该回调方法中返回string类型的业务自定义数据,该数据会写入到崩溃文件中并上传到服务器展示。注意:崩溃回调中返回string类型数据的长度限制为256个字符。
接口示例
UMCrash.registerUMCrashCallback(newUMCrashCallback(){
@Override
publicString onCallback(){
return"崩溃时register的自定义内容字符串";
}
});
上传后即可在错误详情-自定义字段中查看到回调信息

8.2自定义异常接口
如果开发者自己捕获了错误,需要手动上传到【友盟+】服务器可以调用下面两种方法:
方法一:
public static void UMCrash.generateCustomLog(Throwable e,String type)
参数 | 含义 |
e | 错误异常 |
type | 自定义错误的类型 |
方法一示例:
try{ // 抛出异常的代码 }catch(Exception e){ UMCrash.generateCustomLog(e,"UmengException"); }
方法二:
public static void UMCrash.generateCustomLog(String e,String type)
参数 | 含义 |
e | 错误异常 |
type | 自定义错误的类型 |
方法二示例:
String e ="自定义异常代码"; UMCrash.generateCustomLog(e,"UmengException");
使用自定义错误,查看时请在错误列表页面选择【自定义异常】。
8.3卡顿分析
卡顿分析无法做额外配置,默认为开启,如果您需要关闭此采集功能,请参考本文中的采集开关
安卓卡顿分析默认的值为超过2秒计为卡顿,如果您需要设置不同的阈值,可以通过下方的API进行设置,API和示例如下:
/** 设置卡顿阈值的API是通过UMEfs.initConfig(Bundle bundle)方法设置,
* bundle对象中传入对应的key为UMEfs.KEY_PA_TIMEOUT_TIME,
* 对应的值为您设置的卡顿的阈值 *
**/
Bundle bundle = new Bundle();
bundle.putLong(UMEfs.KEY_PA_TIMEOUT_TIME, 2000L);//设置卡顿阈值为2000L
UMEfs.initConfig(bundle);
注意1:阈值限制为大于0且小于等于4,非法值无效SDK取默认值2秒设置;
注意2:需要在初始化之前设置。
8.4网络分析
警告
请务必在此操作前,完成APM相关功能组件的集成,此操作仅代表自动集成网络监控的方法。
适用范围
目前网络监控仅支持监控OkHttp网络请求 ,并且需要手动设置eventListenerFactory和NetworkInterceptor
需要使用OKHttp的最低版本是3.11.0
手动集成
手动集成监控即需要您手动将网络监控 SDK 相关 API 预埋到您项目工程的OkHttp中。
1、设置eventListenerFactory和NetworkInterceptor。
在您build OkHttpClient时,通过OkHttp的eventListenerFactory方法和addNetworkInterceptor方法分别设置事件监听器和拦截器,示例如下:
OkHttpClient okHttpClient = newOkHttpClient.Builder()
//设置事件监听器,OkHttpListener.get()为SDK API
.eventListenerFactory(OkHttpListener.get())
//设置拦截器,new OkHttpInterceptor()为SDK API
.addNetworkInterceptor(new OkHttpInterceptor())
.build();
日志查看是否集成
被采样的状态:打开SDK Log开关,通过NetTrace过滤Logcat信息,可以查看整个网络监控的状态信息,如下:

没有被采样的状态:

8.5启动分析
概述
启动监控用于监控、还原C端用户启动您App时的真实感知情况。分类如下:
首次启动:App安装后的第一次启动
冷启动:App进程被"杀死"(包括手动方式、被动系统回收等),再次触发启动的过程
热启动:App进程存活,再次触发启动的过程(包括前后台切换、back退出再次进入等)
其中,首次启动和冷启动会对启动过程中进行启动时间的分解监控,包括初始化时长、构建时长、页面加载时长三个指标,热启动则只监控启动时长,监控指标说明如下:
首次启动或冷启动时长:从Application的attachbaseContext()开始到第一个Activity的onResume()结束;
热启动时长:如果退出时的Activity存在则从恢复该Activity的onRestart()开始到onResume()结束,如果退出时的Activity不存在则从Activity的onCreate()开始到onResume()结束。
集成方式
说明
请务必在此操作前,完成U-APM相关功能组件的集成,此操作仅代表自动集成启动监控的方法。
手动集成方式
手动集成监控即需要您手动将启动监控 SDK 相关 API 预埋到您项目工程中。
1、在自定义 Application 的 attachBaseContext()方法开始添加如下代码:
LaunchManager.onTraceApp(this, LaunchManager.APP_ATTACH_BASE_CONTEXT, true);
2、在自定义 Application 的 attachBaseContext()方法最后添加如下代码:
LaunchManager.onTraceApp(this, LaunchManager.APP_ATTACH_BASE_CONTEXT, false);
3、在自定义 Application 的 onCreate()方法最后添加如下代码:
LaunchManager.onTraceApp(this, LaunchManager.APP_ON_CREATE, false);
4、在启动阶段页面展示的 Activity 的 onCreate()方法开始添加如下代码:
LaunchManager.onTracePage(this, LaunchManager.PAGE_ON_CREATE, true);
5、在启动阶段页面展示的 Activity 的 onRestart()方法开始添加如下代码:
LaunchManager.onTracePage(this, LaunchManager.PAGE_ON_RE_START, true);
6、在启动阶段页面展示的 Activity 的 onStart()方法开始添加如下代码:
LaunchManager.onTracePage(this, LaunchManager.PAGE_ON_START, true);
7、在启动阶段页面展示的 Activity 的 onResume()方法最后添加如下代码:
LaunchManager.onTracePage(this, LaunchManager.PAGE_ON_RESUME, false);
8、在启动阶段页面展示的 Activity 的 onStop()方法开始添加如下代码:
LaunchManager.onTracePage(this, LaunchManager.PAGE_ON_STOP, true);
自动集成方式
1、依赖插件。
打开您工程根目录的build.gradle,在dependencies中添加如下:
classpath "com.umeng.umsdk:apm-plugin:1.0.1"
注意:确保您已在工程根目录的build.gradle中添加Maven地址。
示例如下:

2、配置插件。
打开您App的build.gradle添加使用插件,在文件头添加代码如下:
apply plugin: 'com.efs.sdk.plugin'
同时添加插件的相关配置,代码如下:
efs {
//是否对启动过程进程插桩的开关,如果使用自动集成监控则必须开启,false则不开启启动插件
enable = true
//白名单,支持包力度,必须填写,如填写自己应用的包名
whiteList = [
"您自己的包名路径"
]
}
完整示例:

自定义启动阶段数据
概念
如果您想在启动监控过程中加入自定义的监控阶段,比如初始化业务数据(initData)、初始化页面组件(initView)等,您可以使用自定义启动阶段API加入您自定义的启动阶段数据。
注意:
说明
1、自定义启动阶段只支持冷启动阶段,热启动不支持
2、如果自定义启动阶段超过SDK所定义的启动结束时间点,则会被SDK丢弃
方法
在您自定义阶段开始处添加如下API:
注:自定义阶段key长度不可以超过10个字符
/**
* 参数1:上下文
* 参数2:自定义阶段key,需要和onTraceEnd配对使用
* 参数3:时间戳
*/
LaunchManager.onTraceBegin(context, "自定义阶段key_2", System.currentTimeMillis());
在您自定义阶段结束处添加如下API:
注:自定义阶段key长度不可以超过10个字符
/**
* 参数1:上下文
* 参数2:自定义阶段key,需要和onTraceBgin配对使用
* 参数3:时间戳
*/
LaunchManager.onTraceEnd(context, "自定义阶段key_1", System.currentTimeMillis());
代码示例:
//监控initData()方法在启动阶段的耗时
LaunchManager.onTraceBegin(MainActivity.this, "initData", System.currentTimeMillis());
initData();
LaunchManager.onTraceEnd(MainActivity.this, "initData", System.currentTimeMillis());
结果验证
集成完成启动App,过滤efs.px.api,可以看到如下启动数据发送成功相关信息,即表示启动数据成功上报。

8.6内存分析
内存分析支持OOM异常和内存占用指标。
OOM异常是崩溃分析的子集,因此不单独提供开关配置,是否采集OOM与是否采集Crash同步,如您需要关闭某类崩溃,可通过【集成接入】-【采集开关】调整。
内存占用,需要接入U-APM SDK 1.4.0及以上版本,并建议搭配最新版本Common接入, 如您不希望采集内存占用相关指标,可通过【集成接入】-【采集开关】调整。
8.7App 打通 H5
集成友盟JS SDK的网页在嵌入到App后,JS SDK采集到的数据可以通过App端上传到服务器,该功能默认关闭。如果开启,需要在每一个webview loadUrl前调用如下方法:
//以下方法仅支持U-APM Android 1.6.0.001及以上版本
H5Manager.enableJavaScriptBridge(webView);
webView.loadUrl("https://www.demo.com");
注意:
在API 16及以下版本中,注入JavaScript有安全漏洞,请谨慎使用。
8.8 原生页面
自动集成
1、依赖插件。 打开您工程根目录的build.gradle,在dependencies中添加如下:
classpath "com.umeng.umsdk:apm-plugin:1.0.0"
注意:确保您已在工程根目录的build.gradle中添加Maven地址。
示例如下:

2、配置插件。 打开您App的build.gradle添加使用插件,在文件头添加代码如下:
apply plugin: 'com.efs.sdk.plugin'
同时添加插件的相关配置,代码如下:
efs {
//是否对启动过程进程插桩的开关,如果使用自动集成监控则必须开启,false则不开启启动插件
enable = true
//白名单,支持包力度,必须填写,如填写自己应用的包名
whiteList = [
"您自己的包名路径"
]
}
示例如下:

自定义页面阶段数据
概念 如果您想在页面监控过程中加入自定义的监控阶段,比如初始化业务数据(initData)、初始化页面组件(initView)等,您可以使用自定义页面阶段API加入您自定义的页面阶段数据。
方法 在您自定义阶段开始处添加如下API: 注:1、自定义阶段key长度不可以超过10个字符;2、key的名称不能以"UM_"开头;3、单个页面使用上限为6个,超出则过滤。
/**
* 参数1: 当前activity对象
* 参数2: 自定义阶段key,需要和onTracePageEnd配对使用
*/
PageManger.onTracePageBegin(MainActivity.this, "initView");
在您自定义阶段结束处添加如下API: 注:自定义阶段key长度不可以超过10个字符;2、key的名称不能以"UM_"开头;3、单个页面使用上限为6个,超出则过滤。
/**
* 参数1: 当前activity对象
* 参数2: 自定义阶段key,需要和onTracePageBegin配对使用
*/
PageManger.onTracePageEnd(MainActivity.this, "initView");
代码示例:
//监控initView()方法在页面阶段的耗时
PageManger.onTracePageBegin(MainActivity.this, "initView");
initView();
PageManger.onTracePageEnd(this, "initView");
8.9采集开关
注:您在产品后台「开关与采样配置」中设置的开关和采样率优先级高于在SDK中设置的开关,SDK会间隔8小时同步是否有开关和采样配置更新的请求
本采集开关适用于开发者在不想使用某个U-APM 监控模块时可灵活自定义采集范围。如目前提供功能都需要采集,则不需要使用该开关,如需要调整某个模块,可按照下面bundle控制说明,选择key进行设置。
注意
此API需要在调用初始化方法前使用
/**
* 通过Bundle中指定的key和key的value值(boolean类型)来控制该key对应APM模块的关闭
*/
UMCrash.initConfig(Bundle args)
//用于控制UMCrash.KEY_ENABLE_CRASH_JAVA
//UMCrash.KEY_ENABLE_CRASH_NATIVE
//UMCrash.KEY_ENABLE_ANR
UMEfs.initConfig(Bundle args)
//用于控制UMEfs.KEY_ENABLE_PA
//UMEfs.KEY_ENABLE_LAUNCH
//UMEfs.KEY_ENABLE_MEM
//UMEfs.KEY_ENABLE_NET
//UMEfs.KEY_ENABLE_H5PAGE
//UMEfs.KEY_ENABLE_PAGE
Bundle控制说明:
key | 说明 | 开关级别 |
UMCrash.KEY_ENABLE_CRASH_JAVA | 用于关闭java crash捕获,默认为true可设置为false进行关闭 | 二级 |
UMCrash.KEY_ENABLE_CRASH_NATIVE | 用于关闭native crash捕获,默认为true可设置为false进行关闭 | 二级 |
UMCrash.KEY_ENABLE_ANR | 用于关闭ANR捕获,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_PA | 用于关闭卡顿捕获,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_LAUNCH | 用于关闭启动捕获,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_MEM | 用于关闭内存占用捕获,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_NET | 用于关闭网络分析捕获,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_H5PAGE | 用于关闭App与H5打通开关,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_PAGE | 用于关闭Page开关,默认为true可设置为false进行关闭 | 一级 |
UMEfs.KEY_ENABLE_CODE_LOG | 用于关闭日志回捞开关,默认为true可设置为false进行关闭 | 一级 |
示例
UMConfigure.setLogEnabled(true);
Bundle bundle = new Bundle();
bundle.putBoolean(UMCrash.KEY_ENABLE_CRASH_JAVA, true);
bundle.putBoolean(UMCrash.KEY_ENABLE_CRASH_NATIVE, true);
bundle.putBoolean(UMCrash.KEY_ENABLE_ANR, false);
bundle.putBoolean(UMEfs.KEY_ENABLE_PA, false);
bundle.putBoolean(UMEfs.KEY_ENABLE_LAUNCH, false);
bundle.putBoolean(UMEfs.KEY_ENABLE_MEM, false);
bundle.putBoolean(UMEfs.KEY_ENABLE_H5PAGE, false);
bundle.putBoolean(UMEfs.KEY_ENABLE_CODE_LOG, false);
UMCrash.initConfig(bundle);
UMConfigure.init(this, "54d32f63fd98c54469***b", "umeng", UMConfigure.DEVICE_TYPE_PHONE, null);
说明
1、由于启动监控早于SDK初始化,所以彻底去掉启动监控还需关闭插件插桩或去掉手动API埋点。
2、卡顿开关关闭情况下不会对卡顿模块进行初始化,并输出如下LOG内容:enablePaLog is false 。
3、启动开关关闭情况下不会对卡顿模块进行初始化,并输出如下LOG内容:enableLaunchLog is false 。
4、内存开关关闭情况下不会对内存模块进行初始化,并输出如下LOG内容: enableMemLog is false 。
5、日志回捞关闭情况下不会对日志回捞模块进行初始化,并输出如下LOG内容: enable codeLog is false 。
8.10符号表
什么是符号表
符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:<起始地址> <结束地址> <函数> [<文件名:行号>]为了能快速并准确地定位用户APP发生Crash的代码位置,我们使用符号表对APP发生Crash的程序堆栈进行解析和还原。 因此在使用U-APM还原时需要先上传符号表!
为什么要上传符号表
为了能快速并准确地定位用户APP发生Crash的代码位置,使用符号表对APP发生Crash的程序堆栈进行解析和还原。
举一个例子

性能监控提供了手动上传符号表。
Android 打包符号表方式
如何打包符号表
Java 符号
多个mapping文件请自行处理追加到一个文件中,最终命名为mapping.txt,并打包成zip文件,如果需要同时包含so符号,可以把so文件打包在一起。(具体结构可参考下面“符号表文件建议示例”)
Android so库
保证符号表的so文件与发布的so文件同名,so压缩前最大支持400M;如果一个版本里包含同文件名,不同架构的so,可以压缩到不同的目录中,反符号化时需要通过buildid去关联;建议编译时使用-g参数,带上debug信息,崩溃堆栈可以解析到代码行级,实际发布时,再使用strip命令去掉调试信息;如果不带debug信息,则只能定位到函数名级下列情况下,需要so文件带有buildid
不同CPU架构的so文件名一样,放在不同的路径下
同一个应用版本里,可能有多个版本的so库,使用了动态加载的技术如何生成带buildid的so,请检查编译参数,确保没有带”—build-id=none”,如果还是没有buildid,可以添加编译参数”ld_flags += -Wl,--build-id=sha1”可通过file命令检查so文件是否带buildid,调试信息
符号文件建议示例
xxx.zip|— mapping.txt —多个mapping需要自行合并
|— libxx1.so —要求与发布的so同名
|— libxx
|— libxx3.so —同文件名,多个架构放不同的目录
|— x86
|— libxx3.so —同文件名,多个架构放不同的目录
已经上传的符号表可以在符号表管理页面进行查看

当前支持上传方式:后台手动上传(最大支持400M)
版本选择
当前支持现有版本列表和手动输入两种方式:
如果是已经有错误上报到U-APM后台的版本,可以直接在上传符号表时的版本下拉框中选择
如果是即将发布的新版本,支持手动输入版本号,请输入与新版本完全一致的内容,并点击‘添加版本号‘即可手动添加

手动上传方式
按照文档说明将符号表文件压缩到一起:查看【如何打包符号表】
登录平台,找到需要上传的符号表应用,点击顶部的设置进入应用设置界面
点击符号表管理 ,点击上传,将第一步压缩好的符号表文件上传即可
8.11设置HTTP接口API
//isHttpsProtocol默认为true,为false则SDK本地默认发送http请求 UMEfs.setRequestProtocol(boolean isHttpsProtocol);
接口说明:
1、该接口仅影响UAPM 性能部分发送请求,crash部分不受该接口控制;
2、该接口需要在初始化SDK之前设置;
3、用户可通过该接口修改SDK本地是以HTTP头发送还是HTTPS头发送,默认SDK是以HTTPS头发送,并且可以通过云控配置动态下发修改,并且云控下发会覆盖该接口的设置;
4、通过setCustomDomainEfs接口传入的域名中的HTTP或HTTPS头接口内会自动切掉,以SDK默认值(HTTPS头)或setRequestProtocol接口或云控决定SDK使用HTTP或HTTPS。
8.12日志回捞
设置回捞标识
您可以通过如下接口设置回捞标识:
Bundle bundle = new Bundle();
//设置回捞标识为android0911
bundle.putString(UMEfs.KEY_LOG_USER_ID, "android0911");
UMEfs.initConfig(bundle);
注意:
1)该设置必须在初始化SDK之前完成,运行时不可再次设置
2)回捞标识不能为空,且长度不能超过128
3)如果不设置回捞标识,默认以UMID作为标识回捞
日志记录
您可以通过如下接口完成相关日志的记录:
ULog.v("日志TAG", "日志内容"); ULog.d("日志TAG", "日志内容"); ULog.i("日志TAG", "日志内容"); ULog.w("日志TAG", "日志内容"); ULog.e("日志TAG", "日志内容");
主要:
1)共提供五种日志等级,包括:v/d/i/w/e
2)参数1为日志的TAG,不能为空或长度超过64,参数2为日志的内容,不能为空或长度超过1024
日志策略
1)日志持久化存储上限为5MB(该参数可通过云配修改),当达到上限时则仅保留最近7天的日志,如果最近7天日志达到上限则不再继续存储日志
2)触发日志持久化存储:2.1)前后台切换;2.2)缓存数据达到上限则进行持久化日志存储
3)当回捞任务下发到本地,并成功加载后,则进行回捞任务和本地日志的匹配,匹配到的日志开始上传,当前进程正在产生的日志需要下次启动后匹配任务继续上传
日志排查
1)日志回捞模块开启,输出如下日志:
enable codeLog is true
2)正确读取并加载日志任务,输出如下日志:
09-13 14:56:28.988 15994-15994/com.efs.demo I/ULogConfigManager: [log register] begin. 09-13 14:56:29.704 15994-15994/com.efs.demo I/ULogConfigManager: [log register] call back config. 09-13 14:56:29.709 15994-15994/com.efs.demo I/ULogConfigManager: [log register] save did is 9560fe0f75e7c92fff351d537633a91cia 09-13 14:56:29.709 15994-15994/com.efs.demo I/ULogConfigManager: [log register] save uid is android0911 09-13 14:56:29.710 15994-15994/com.efs.demo I/ULogConfigManager: [log register] save task id is 1660130437264, task is {"task_etime":1663257599000,"target_type":0,"task_id":"1660130437264","task_btime":1662307200000,"task_type":0} 09-13 14:56:29.710 15994-15994/com.efs.demo I/ULogConfigManager: [log register] add mem task id is 1660130437264 09-13 14:56:29.710 15994-15994/com.efs.demo I/ULogConfigManager: [log register] save task id is 1660130437265, task is {"task_etime":1663257599000,"target_type":1,"task_id":"1660130437265","task_btime":1662307200000,"task_type":0} 09-13 14:56:29.710 15994-15994/com.efs.demo I/ULogConfigManager: [log register] add mem task id is 1660130437265 09-13 14:56:29.710 15994-15994/com.efs.demo I/ULogConfigManager: [log register] save task id set is 1660130437264_1660130437265
3)持久化存储日志(如前后台切换),输出如下日志:
09-13 15:06:23.445 15994-16722/com.efs.demo I/efs.base: {"fr":"android","sdk":23,"others_OS":"Android","stime":1663052188738,"dsp_h":1920,"rom":"6.0.1","sdk_ver":"1.3.11.umeng","w_tm":1663052783,"um_access":"wifi","lang":"zh","um_umid_header":"aid03bc207717fd2238c5d8bf93ed4fffb","pkg":"com.efs.demo","type":"codelogperf","dsp_w":1080,"um_network_type":0,"wid":"54d8e67e-0a4e-4e11-9517-08ac993aa670","log_uid":"android0911","pid":15994,"ps":"com.efs.demo","build_model":"MI 4LTE","appid":"ez2cookeijezdgu3nxmci6zt","um_app_carrier":"","ctime":1663052783,"net":"wifi","um_crash_sdk_version":"efs.1.6.0.001.200","um_os":"android","vcode":"1","tzone":"Asia\/Shanghai","um_app_channel":"Umeng","brand":"xiaomi","log_did":"9560fe0f75e7c92fff351d537633a91cia","codelog":{"taskid":"","status":0,"time_start":1663052782368,"time_end":1663052783439,"uid":"android0911","did":"9560fe0f75e7c92fff351d537633a91cia","body":[{"tag":"walle","msg":"button 1 --->>> ","level":0,"time":1663052782367,"process":"com.efs.demo","thread":"main"},{"tag":"walle","msg":"button 1 --->>> ","level":2,"time":1663052782370,"process":"com.efs.demo","thread":"main"}]},"uid":"54d8e67e-0a4e-4e11-9517-08ac993aa670","ver":"1.0","model":"mi-4lte"} 09-13 15:06:23.459 15994-16077/com.efs.demo I/RecordLogCacheProcessor: save file, type is codelogperf 09-13 15:06:23.463 15994-16077/com.efs.demo I/RecordLogCacheProcessor: upload file, name is codelogperf_none_1_1_15994_2442_1663052783458_android0911_9560fe0f75e7c92fff351d537633a91cia_1663052782368_1663052783439
查看data/data/<你的app>/app_UApm/<你的appkey>/upload_codelog中有日志文件,则表示日志保存成功
4)日志匹配并上传成功,输出如下日志:
09-13 15:06:39.255 15994-16077/com.efs.demo I/efs.cache: [-->>] add file is codelogperf_gzip_2_1_15994_3356_1663052783463_android0911_9560fe0f75e7c92fff351d537633a91cia_1663052782368_1663052783439 09-13 15:06:39.262 15994-16141/com.efs.demo I/efs.LogSendAction.Codelog: send data url is http://aplus2-portal-lite.emas-poc.com 09-13 15:06:39.272 15994-16141/com.efs.demo I/efs.px.api: Upload file, url is http://aplus2-portal-lite.emas-poc.com/apm_logs 09-13 15:06:39.478 15994-16141/com.efs.demo I/efs.px.api: upload result : true, resp is HttpResponse {succ=true, code=200, data='{"msg":"成功","code":0,"cip":"XXX.XX.XX.XXX","stm":1663052801}', extra={req_url=http://aplus2-portal-lite.emas-poc.com/apm_logs, flow_limit=true, biz_code=0, size=592, type=codelogperf}} 09-13 15:06:39.480 15994-16077/com.efs.demo I/efs.send_log: send secess.
附录-SDK上报策略
如果您创建了自定义异常,则需要存在自动采集的崩溃/ANR发生时一起上报
测试中请关注SDK上报策略,当日单设备达到限制后无法再上报数据
错误类型 | 上报策略 |
Java | 崩溃捕获后会尝试立刻发送,如果失败就下次启动发送同时通过流量 + 数量的限制,详细请见下方表格 |
Native | |
ANR | |
自定义异常 | 发生后跟随Java/Native/ANR 错误上报 |
卡顿/启动/网络/H5页面分析 | 实时上报 |
错误上报的流量+数量限制: | 目前默认值 |
允许保留在崩溃日志目录 mCrashLogsFolderName 下最大的崩溃日志条数。在生成日志前,如果发现崩溃日志文件数达到限制的条数,就会删除最早生成的那条崩溃日志。每删除一条崩溃日志,统计项 CrashStatKey.LOG_ABANDONED_FILE 和 CrashStatKey.LOG_ABANDONED_BUILTIN_FILE 都会加 1 | 15 |
允许保留在崩溃日志目录 mCrashLogsFolderName 下最大的自定义日志数。在生成自定义日志前,如果发现自定义日志文件数达到限制,就会删除最早生成的那个自定义日志。每删除一条自定义日志,统计项 CrashStatKey.LOG_ABANDONED_FILE 和 CrashStatKey.LOG_ABANDONED_CUSTOM_FILE 都会加 1。 | 10 |
java 崩溃日志中,获取 logcat 的最大行数 | 1500 |
native 崩溃日志中,获取 logcat 的最大行数 | 3000 |
anr 日志中,获取 logcat 的最大行数 | 1000 |
是否同步上传主进程初始化过程中产生的崩溃日志。开启该选项时,如果 SDK 检测到主进程发生崩溃,在生成完该崩溃日志后,SDK 会尝试立即将崩溃日志上传(以防止该场景下的稳定崩溃收集不到)。该开关仅在Java和 native 崩溃中生效,自定义日志无效。SDK 判断主进程的条件为:Package Name 与 /proc/self/cmdline 中的进程名相等。 | true |
是否生成完日志后立即上传。该开关针对除自定义日志以外的日志有效,自定义日志由日志生成时指定是否立即上传。 | true |
是否在发现 APP 当前的版本与上次运行时的版本不一致时,清除所有的崩溃统计数据。版本是否一致,是根据版本号 VersionInfo.mVersion、子版本号 VersionInfo.mSubVersion、打包流水号 VersionInfo.mBuildId 判断,任何一个不一样,都会认为是不同版本。 | false |
是否在生成完崩溃日志后,使用 gz 算法压缩崩溃日志。压缩成功后,原日志被删除;压缩失败,原日志将保留 | true |
是否在生成完崩溃日志后,使用默认算法加密崩溃日志。加密成功后,原日志被删除;加密失败,原日志将保留 | false |
生成日志时,每个日志允许写入的最大字节数。 当达到指定的字节数时,会将剩余的全部丢弃。日志的总长度、丢弃字节数等信息,在日志最后会有记录。对 JAVA, NATIVE, ANR 日志都有效;为 <= 0 的值时,表示不限制。 | 1024*1024 |
在上传崩溃日志时,上传的单个日志允许的最大字节数。超过此限制时,将放弃上传该日志并直接删除,同时将统计项 CrashStatKey.LOG_LARGE_FILE加 1 。其对所有类型的日志有效。为 <= 0 的值时,表示不限制。 | 800*1024 |
每24小时内,允许上传日志总共的最大字节数。超过时,将放弃日志的上传,日志将保留在磁盘;超过 24 小时后,再次调用上传接口时,再上传日志。为 < 0 的值时,表示不限制。每次尝试上传发现达到该限制时,统计项 CrashStatKey.LOG_UPLOAD_LIMIT 和 CrashStatKey.LOG_UPLOAD_BYTES_LIMIT 都会加 1。 | 1.5*1024*1024 |
每 24 小时内上传的最大崩溃日志条数。每次尝试上传发现达到该限制时,统计项 CrashStatKey.LOG_UPLOAD_LIMIT 和 CrashStatKey.LOG_UPLOAD_BUILTIN_LIMIT 都会加 1。其自版本 3.0.0 从 mMaxUploadCrashLogCountPerDay 重命名而来。 | 25 |
每 24 小时内上传的最大自定义日志条数。每次尝试上传发现达到该限制时,统计项 CrashStatKey.LOG_UPLOAD_LIMIT 和 CrashStatKey.LOG_UPLOAD_CUSTOM_LIMIT 都会加 1。 | 20 |
每 24 小时内每种自定义类型的日志允许生成的最大条数。不同类型的自定义日志条数会分别计数。 | 6 |
每个进程允许生成的最大 ANR 日志条数。 | 3 |
崩溃生成日志后,不自动重启 | true |
是否在 SDK 处理完 java 异常且生成完 java 崩溃日志后,将异常信息通知给 SDK 初始化之前,其他人(系统)注册的 UncaughtExceptionHandler。 | true |
是否在 SDK 处理完 native 崩溃信号且生成完 native 崩溃日志后,将崩溃信号通知给 SDK 初始化之前,其他人(系统)注册的信号处理函数。 | false |
自动更新当前 CPU 使用率等信息的时间间隔,单位为秒(s)。 | 50 |