本文介绍如何在系统应用中集成LeakCanary。由于很多系统应用不使用gradle,且通过Android.mk来进行编译,因此无法使用类似gradle的方式添加依赖来完成对LeakCanary的集成和使用。
1. 源码下载
LeakCanary的源码链接 https://github.com/square/leakcanary,通过 git clone
或者 zip 的方式将源码下载到本地,源码目录如下:
将 leakcanary-analyzer
,leakcanary-android
和 leakcanary-watcher
复制到系统应用源码根目录下。
2. 添加编译支持(修改Android.mk)
将上述3个java代码目录添加到编译树中:
LOCAL_SRC_FILES += $(call all-java-files-under, leakcanary-analyzer/) \
$(call all-java-files-under, leakcanary-android/) \
$(call all-java-files-under, leakcanary-watcher/)
将 leakcanary-android 目录下的 res 目录添加到资源文件编译:
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/leakcanary-android/src/main/res
添加 haha
和 trove
的 jar 包到系统应用源码 libs 文件夹中,haha-2.0.3.jar 和 trove-3.0.2.jar 的下载链接:
https://pan.baidu.com/s/1dto2NcgvxEdiA3lGXVKX0A 提取码: qjqy
将这两个 jar 包加入编译:
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES += \
haha:libs/haha-2.0.3.jar \
trove:libs/trove-3.0.2.jar
LOCAL_STATIC_JAVA_LIBRARIES += \
haha \
trove
3. 修改 AndroidManifest.xml
需要将 leakcanary-android 中声明的 Activity,Service,Provider 等组件以及权限申请加入到 AndroidManifest.xml 清单文件中:
4. 初始化 LeakCanary
在应用 Application (如果没有,需要手写一个并在 AndroidManifest.xml 文件中注册)的 onCreate 函数中初始化 LeakCanary。
@Override
public void onCreate() {
super.onCreate();
if (!LeakCanary.isInAnalyzerProcess(this)) {
sRefWatcher = LeakCanary.install(this);
}
}
5. 其他编译错误解决
packages/apps/****/leakcanary-android/src/main/res/values/leak_canary_public.xml:19: error: No 'id' attribute supplied , and no previous id defined in this file.
packages/apps/****/leakcanary-android/src/main/res/values/leak_canary_public.xml:20: error: No 'id' attribute supplied , and no previous id defined in this file.
packages/apps/****/leakcanary-android/src/main/res/values/leak_canary_public.xml:21: error: No 'id' attribute supplied , and no previous id defined in this file.
解决方法:直接删除 leak_canary_public.xml。
packages/apps/****/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java:31: 错误: 找不到符号
import gnu.trove.THashMap;
packages/apps/****/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java:32: 错误: 找不到符号
import gnu.trove.TObjectProcedure;
解决方法:在 HeapAnalyzer.java 文件中将 “import gnu.trove.THashMap” 修改成 “import gnu.trove.map.hash.THashMap”,将 “import gnu.trove.TObjectProcedure” 修改成 “import gnu.trove.procedure.TObjectProcedure”。
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:22: 错误: 程序包org.junit不存在
import org.junit.Before;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:23: 错误: 程序包org.junit不存在
import org.junit.Test;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:24: 错误: 程序包org.junit.runner不存在
import org.junit.runner.RunWith;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:25: 错误: 程序包org.junit.runners不存在
import org.junit.runners.Parameterized;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:34: 错误: 程序包org.hamcrest.core不存在
import static org.hamcrest.core.StringContains.containsString;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:34: 错误: 仅从类和接口静态导入
import static org.hamcrest.core.StringContains.containsString;
^
packages/apps/****/leakcanary-analyzer/src/test/java/com/squareup/leakcanary/AsyncTaskLeakTest.java:35: 错误: 程序包org.junit不存在
import static org.junit.Assert.assertEquals;
解决方法:直接删除所有的 Test 类文件
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/DisplayLeakService.java:57: 错误: 程序包R不存在
String contentTitle = getString(R.string.leak_canary_no_leak_title);
^
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/DisplayLeakService.java:58: 错误: 程序包R不存在
String contentText = getString(R.string.leak_canary_no_leak_text);
解决办法:将 LeakCanary 中所有使用到 “R” 的地方都替换成 import 当前系统应用的 “R”。
import static com.squareup.leakcanary.BuildConfig.GIT_SHA;
^
符号: 类 BuildConfig
位置: 程序包 com.squareup.leakcanary
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:30: 错误: 仅从类和接口静态导入
import static com.squareup.leakcanary.BuildConfig.GIT_SHA;
^
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:31: 错误: 找不到符号
import static com.squareup.leakcanary.BuildConfig.LIBRARY_VERSION;
^
符号: 类 BuildConfig
位置: 程序包 com.squareup.leakcanary
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java:31: 错误: 仅从类和接口静态导入
import static com.squareup.leakcanary.BuildConfig.LIBRARY_VERSION;
^
解决方法:在 leakcanary-android/src/main/java/com/squareup/leakcanary/ 文件夹下创建一个 BuildConfig.java 文件,在其中添加如下内容:public static String GIT_SHA = "GIT_SHA"; public static String LIBRARY_VERSION = "LIBRARY_VERSION";
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/AndroidOFragmentRefWatcher.java:22: 错误: 找不到符号
import android.support.annotation.RequiresApi;
^
符号: 类 RequiresApi
位置: 程序包 android.support.annotation
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/AndroidOFragmentRefWatcher.java:27: 错误: 找不到符号
@RequiresApi(Build.VERSION_CODES.O) //
解决方法:去除 RequiresApi 注解及相关的 import。
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/AbstractAnalysisResultService.java:47: 错误: 找不到符号
ContextCompat.startForegroundService(context, intent);
^
符号: 方法 startForegroundService(Context,Intent)
位置: 类 ContextCompat
packages/apps/****/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/HeapAnalyzerService.java:49: 错误: 找不到符号
ContextCompat.startForegroundService(context, intent);
^
符号: 方法 startForegroundService(Context,Intent)
位置: 类 ContextCompat
解决方法:将 “ContextCompat.startForegroundService(context, intent)” 修改成 context.startForegroundService(intent)
。