一、介紹:
最近做app性能優化增加了幾個第三方性能檢測框架:
1、leakcanary(內存泄漏檢測)
2、blockcanary(耗時檢測工具)
因爲項目開發時在android studio工具編譯但在完整編譯時是用make方式和整個項目一起編譯,所以需要在AS編譯時自動把上面性能檢測工具編入方便開發自我調試,但在make編譯版本不能帶上上面工具(各種提示和日誌影響用戶體驗),同時也要滿足所有開發使用同一份代碼互不影響,git庫使用同一份代碼大家都能用到上面功能。
針對上面情況需要差異化編譯代碼,並且兼容android studio和make腳本編譯方式。
二、分析
1.leakcanary和blockcanary工具使用方法都只是需要在application類中做初始化即可,不涉及其它代碼,所以需要對application進行差異化區分。
2.application需要在AndroidManifest.xml中聲明,所以需要差異化AndroidManifest.xml文件。
3.添加leakcanary和blockcanary工具有兩種方式:
(1)下載源碼或jar包
(2)直接通過gradle引入
這兩種方法都可以我選擇的是第二種,因爲添加上面工具主要是給開發自己使用所以需要和編譯給其它人使用區分開,這個紀要用到多渠道打包方式。
4.make編譯是給客戶或測試的所以不需要編譯上面工具,需要區分。
三、實施
根據以上分析我們需要做以下幾個工作:
一.創建一個獨立目錄存放差異代碼(這個目錄不能在其它被包含的目錄內否則可能會被其它代碼編譯進去)
我這裏主要是需要application文件所以修改了上面幾個文件res,libs等目錄如果用到了也可以添加
1.因爲項目開始沒有重寫application,所以新建了一個,如果之前已經重寫了則需要在原來的基礎上加上新增代碼(保證原有功能)
import android.app.Application;
import android.content.Context;
import com.github.moduth.blockcanary.BlockCanary;
import com.squareup.leakcanary.LeakCanary;
public class LauncherApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
//耗時檢測初始化
BlockCanary.install(this, new AppContext()).start();
//內存泄漏初始化
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
}
public static Context getAppContext(){
return mContext;
}
}
2.下面是新增文件給BlockCanary配置參數
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.android.launcher3.util.RyLogger;
import com.github.moduth.blockcanary.BlockCanaryContext;
public class AppContext extends BlockCanaryContext {
private static final String TAG = "AppContext";
@Override
public String provideQualifier() {
String qualifier = "";
try {
PackageInfo info = LauncherApplication.getAppContext().getPackageManager()
.getPackageInfo(LauncherApplication.getAppContext().getPackageName(), 0);
qualifier += info.versionCode + "_" + info.versionName + "_YYB";
} catch (PackageManager.NameNotFoundException e) {
RyLogger.e(TAG, "provideQualifier exception"+e);
}
return qualifier;
}
@Override
public int provideBlockThreshold() {
//阻塞時間超過多少秒發通知
return 1000;
}
@Override
public boolean displayNotification() {
return true;
}
@Override
public boolean stopWhenDebugging() {
return false;
}
}
3.最後是AndroidManifest.xml文件同樣需要保持原有代碼並修改application,主要是替換application文件
<application
android:name=".LauncherApplication"
android:backupAgent=".LauncherBackupAgent"
android:fullBackupContent="@xml/backupscheme"
android:fullBackupOnly="true"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher_home"
android:label="@string/derived_app_name"
android:theme="@style/AppTheme"
android:largeHeap="@bool/config_largeHeap"
android:networkSecurityConfig="@xml/network_security_config"
android:restoreAnyVersion="true"
android:supportsRtl="true">
二.修改build.gradle
1.主要是添加代碼差異化編譯,新增的代碼
//新增目錄需要編譯內容,src,res,libs,manifest
debug {
java.srcDirs = ['debug_src']
jniLibs.srcDirs = ['libs']
res.srcDirs = ['res']
manifest.srcFile "debug_src/AndroidManifest.xml"
}
sourceSets {
main {
res.srcDirs = ['res']
java.srcDirs = ['src']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
manifest.srcFile 'AndroidManifest-common.xml'
proto {
srcDir 'protos/'
srcDir 'proto_overrides/'
}
}
//新增目錄需要編譯內容,src,res,libs,manifest
debug {
java.srcDirs = ['debug_src']
jniLibs.srcDirs = ['libs']
res.srcDirs = ['res']
manifest.srcFile "debug_src/AndroidManifest.xml"
}
androidTest {
res.srcDirs = ['tests/res']
java.srcDirs = ['tests/src']
manifest.srcFile "tests/AndroidManifest-common.xml"
}
androidTestDebug {
manifest.srcFile "tests/AndroidManifest.xml"
}
aosp {
java.srcDirs = ['src_flags', "src_ui_overrides"]
}
}
2.添加引入方式
當前使用了兩種方式一種時jar包一種是Implementation引入
dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
// Optional, if you use support library fragments:
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.1'
}
三、make文件差異化編譯
1.如果需要增加新工具到make中需要做以下工作
include $(CLEAR_VARS)
LOCAL_MODULE := blockcanary #別名
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_SRC_FILES := libs/blockcanary.jar #包名
LOCAL_UNINSTALLABLE_MODULE := true
#LOCAL_SDK_VERSION := current
LOCAL_PRIVATE_PLATFORM_APIS:=true
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := libxypatch3
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES_32 := libs/armeabi/libxypatch.so
LOCAL_SRC_FILES_64 := libs/arm64-v8a/libxypatch.so
LOCAL_MULTILIB := both
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
include $(BUILD_PREBUILT)
LOCAL_STATIC_JAVA_LIBRARIES += blockcanary \ libxypatch3 #加入靜態庫
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
$(call all-java-files-under, src_ui_overrides) \
$(call all-java-files-under, src_flags) \
$(call all-proto-files-under, protos) \
$(call all-proto-files-under, debug_src/src) #新增
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/debug_src/res #新增
LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/debug_src/AndroidManifest-common.xml #新增
2.如果不需要添加到make編譯中
需要注意新增的debug_src目錄是否被之前編譯目錄包含如果已經被包含則需要移動到其它目錄下,防止被編譯
總結:
差異化編譯需要注意:
1.差異化目錄是否是獨立的沒有被其他編譯包含
2.對應的源碼,資源,libs,AndroidManifest.xml,是否修改到了並在build.gradle裏面差異化配置
3.新增的功能是否會影響原有功能
4.新增差異化一定寫上註釋