android應用上線前應該做的一些事一

一、apk簽名(必須)
1.apk簽名(數字簽名)
apk簽名:開發者(開發商)通過數字證書(也可以叫簽名文件),給apk應用打上帶有個人(公司)信息的標記,以表示自己是該應用的開發者或擁有者。簽名後的apk解壓後能看到META-INF文件夾,並且裏面會有3個簽名相關的文件(MANIFEST.MF,CERT.SF,CERT.RSA)

數字簽名: 哈希算法(sha1, md5) + 私鑰加密

查看apk的擁有者


keytool -printcert -file CERT.RSA
關於Android數字簽名相關事項:

所有的應用都必須進行簽名,android系統不會安裝沒有簽名的應用;

使用不同數字證書籤名的兩個apk,無法實現覆蓋安裝。所以,應用在版本升級打包時必須使用同一個數字證書(keystore文件)進行簽名; 這一點,也保證了用戶手機上已安裝的應用,不會被原作者外的第三者開發的假冒應用安裝替換,因爲第三者不可能持有原作者的數字證書(簽名文件)

應用上線需要release簽名(或者叫正式簽名:指使用個人或公司的簽名文件簽名),不能用debug簽名(開發調試簽名:指使用sdk自帶的簽名文件簽名)

數字證書都是有有效期的,Android只是在應用程序安裝的時候纔會檢查證書的有效期。如果程序已經安裝在系統中,即使證書過期也不會影響程序的正常使用,一般開啓99年就好了

apk簽名可以使用自簽名的數字證書(自己創建的keystore簽名文件),不需要使用CA機構認證的數字證書(需要給CA機構付費);


2.生成簽名文件的兩種方式
通過IDE(AndroidStudio, Eclipse)生成


通過命令行keytool命令生成

keytool -genkeypair -validity [簽名文件的有效期,單位爲天] -keystore [keystore簽名文件(數字證書)] -storepass [store密碼] -alias [密鑰對的別名] -keypass [密鑰密碼]

列表出所有的密鑰對:
keytool -list -v -keystore itheima.keystore
 
參考: https://www.chinassl.net/?f=faq&a=view&r=457
3.AndroidStudio中導出正式簽名包

android {
 
    // 定義簽名用到的數字證書
    signingConfigs {
        config {
            keyAlias 'itheima'
            keyPassword '123456'
            storeFile file('E:/_GZ05/_code/01.ProGuardDemo_AS/itheima.jks')
            storePassword '123456'
        }
    }
    ...
 
    buildTypes {
        // debug簽名, 直接運行使用
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
 
        // 打正式包
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.config  // 使用上面配置的簽名文件進行簽名
        }
    }
}
二、Android代碼混淆(非必須)

1. 混淆簡介
Android代碼混淆是一種應用源代碼保護技術,用來防止別人對apk進行逆向分析;
從Android2.3開始,Google在SDK中加入了一個叫ProGuard的工具,使用它來進行代碼混淆。
proguard是一個壓縮、優化和混淆java字節碼文件的免費工具,其作用:
                刪除代碼中的註釋;

                    刪除代碼中沒有用到的類、字段、方法和屬性;

                    會把代碼中的包名、類名、方法名變量名等修改爲abcd...這種沒有意義的名字,使得反編譯出來的代碼難以閱讀,從而達到防止apk被破解和逆向分析的目的;

                    經過ProGuard混淆後apk安裝包會變小

2. 如何使用Proguard進行代碼混淆?
buildTypes {
    release {
        // 修改此參數爲true,表示要進行混淆
        minifyEnabled true
        // 表示要使用sdk中的proguard-android.txt和當前項目中的proguard-rules.pro指定混淆規則
        // 通常只需修改後者就可以了
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    // 指定jdk爲1.7
    compileOptions {
        targetCompatibility 1.7
        sourceCompatibility 1.7
    }
}
在app下的proguard-rules.pro文件中配置混淆規則
打開gradle窗口,雙擊如下操作菜單項(assembleRelease: 打正式的發佈包,installRelease: 安裝正式的發佈包), 生成出來的apk就是經過混淆的


3. 混淆規則配置[重點]
【注意】:有些java類是不能進行混淆,需要配置混淆規則。

1.所有的第三方包jar/庫, 都不進行混淆。 對於每一個第三方的jar或庫都需要配置如下兩行,其中#號爲註釋,


#com.umeng.analytics:是要配置的第三方庫的包名,配置成包名前綴com.umeng也可以
-dontwarn com.umeng.analytics.**               # 不要提示警告
-keep class com.umeng.analytics.** { *; }      # 對指定的類不進行混淆
2.注意:如果你使用的proguard的版本比較低, 對於每一個jar或第三方依賴, 還需要配置如下一行,不加可能會出現“類1 can't find referenced class 類2”這樣的錯。


-libraryjars libs/umeng-analytics-v5.6.1.jar   
只要用到反射的類都不能進行混淆

3.如果使用了Gson解析json字符串,如果需要如下配置


# 保留要解析的javabean中的泛型信息
-keepattributes Signature
 
# bean包及其子包下, 所有要通過Gson反射解析的javabean都不能進行混淆
-keep class com.xxx.bean.**
-keep class com.xxx.bean.** { *;}
4.如果使用了EventBus, 用來接收事件的以onEvent (onEventMainThread)開頭的方法不能進行混淆:
# 如果用到了WebView中js與java代碼的相互調用,js要調用的java類中的方法不能混淆
-keep class com.xxx.WebViewActivity {
    public *;
}
 
# 回調方法聲明在內部類JsInterface中的配置方法
-keep class com.xxx.WebViewActivity2$JsInterface {
    public *;
}
參考第三方庫的github官方文檔進行混淆規則的配置, 例如下面的這些庫官網上都有混淆配置說明。

https://github.com/bumptech/glide

4.混淆後生成的相關文件

dump.txt
說明 APK 中所有類文件的內部結構。
mapping.txt
提供原始與混淆過的類、方法和字段名稱之間的轉換。
seeds.txt
列出未進行混淆的類和成員。
usage.txt
列出從 APK 移除的代碼。
 
使用mapping.txt文件對出錯日誌還原:
retrace.bat -verbose mapping.txt stacktrace.txt > out.txt
其中mapping.txt文件較爲重要(app/build/output/mapping/mapping.txt),該文件需要存檔,以便用來還原和查看混淆後的出錯日誌;

在使用友盟的bug自動捕獲功能時,需要把mapping.txt上傳到友盟後臺。


三、Android資源混淆(非必須)
通過微信資源混淆工具實現(不是必須: 微信6.0,QQ6.0,網易新聞客戶端)


AndResGuard
對res下的資源文件進行混淆, 將原本冗長的資源路徑變短,例如將res/drawable/wechat變爲r/d/a。
AndResGuard不涉及編譯過程,只需輸入一個apk(簽名未簽名都可以,處理後會直接將原簽名刪除),可得到一個實現資源混淆後的apk;
使用第三方工具AndResGuard-master(微信資源混淆)實現資源混淆;
四、多渠道打包(非必須)
1.gradle打包,2.其他工具打包(美團多渠道)

目的:統計的時候,檢測各個市場的數據


五、apk加固(必須)
三方平臺: 梆梆安全, 360加固保, 愛加密, 阿里聚安全, 娜迦, 騰訊加固(樂固)

操作步驟: 生成一個混淆簽名的正式包 --> 上傳apk --> 下載加固後的apk --> 重新簽名

梆梆安全: https://www.bangcle.com
360加固保: http://jiagu.360.cn/
愛加密: http://www.ijiami.cn/ 加固    效果差一點,還能看得到裏面的類,但是沒有方法體實現。
阿里聚安全: https://jaq.alibaba.com
娜迦: http://www.nagain.com/
騰訊加固: http://wiki.open.qq.com/wiki/%E5%BA%94%E7%94%A8%E5%8A%A0%E5%9B%BA


六、apk瘦身(非必須)
減小apk安裝包的大小


必要性
同樣的功能,apk越小越好,用戶下載動機更大。


瞭解apk的組成
classes.dex: 是java源碼編譯後生成的java字節碼文件
resources.arsc:編譯後的二進制資源文件
AndroidManifest.xml
assets: 目錄可以存放一些配置文件或資源文件
lib: 存放jar包,子目錄armeabi存放的是一些so文件
META-INF: 目錄下存放的是簽名信息,用來保證apk包的完整性和系統的安全
res: apk圖片佈局等資源文件 


輔助分析工具
(1)nimbledroid[瞭解]: 能夠得知app內存使用,網絡使用,磁盤輸入/輸出,文件大小等一些NimbleDroid認爲至關重要的數據; * 官網:https://nimbledroid.com/(無需翻牆,訪問比較慢) * 註冊 * 登錄 * 上傳apk * 生成分析結果圖;

(2)Android Studio 2.3 apk逆向工具--APK Analyzer[推薦] 參考:http://blog.csdn.net/nicolelili1/article/details/52669823

瘦身方案
1.開啓minifyEnabled(開啓混淆功能:會刪除沒用到的類或方法)

2.開啓shrinkResources(去除無用資源:會使用一個像素的圖片替換沒有用到的圖片)


buildTypes {
    release {
        minifyEnabled true
        shrinkResources true // 要與minifyEnable=true同時使用, 否則會出錯
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.config
    }
    debug {
        signingConfig signingConfigs.config
    }
}

//添加如下配置就ok了
lintOptions {
    checkReleaseBuilds false
    abortOnError false // 出錯時繼續執行,不退出
}
3.刪除無用的語言資源(國際化文件)


defaultConfig {
    ... 
    resConfigs "zh" // 默認會保留英文語言包 + 這裏配置的zh中文語言包;
}   
4.對於非透明的大圖,jpg將會比png的大小有顯著的優勢,在啓動頁,活動頁等之類的大圖展示區採用jpg將是明智的選擇;


使用【格式工廠工具】進行轉換:png -> jpg
jpg: 壓縮率較高,但是沒有透明度信息,適用於啓動界面的背景圖片
png: 有透明度信息,壓縮率比jpg較小
bmp: 幾乎沒有壓縮
5.使用tinypng有損壓縮

官方網站: https://tinypng.com/ (無需翻牆)TinyPNG 使用一種智能有損壓縮技術(通過降低圖片中的顏色數量,來減少存儲圖片所需要的數據)來降低PNG圖片的大小。這樣的壓縮對圖片的效果影響是很小的,但是可以大大降低圖片的大小,並且還能保持 PNG 的 alpha 透明度因爲 TinyPNG 將 PNG 圖片壓縮成8位的 PNG(而不是24位),所以它的壓縮比例非常高,至少都有 50% 以上的壓縮比例,有些甚至可以達到70%,並且壓縮之後的圖片和原圖人眼基本看不出區別。
6.使用webp圖片格式


從Android 4.0+開始原生支持,但是不支持包含透明度,直到Android 4.2.1+才支持顯示含透明度的webp,使用的時候需要注意

瞭解webp格式: http://isux.tencent.com/introduction-of-webp.html(WebP探尋之路)

Android中圖片優化之webp使用: http://blog.csdn.net/reboot123/article/details/46552437
android4.0以下使用第三方兼容webp圖片:http://blog.csdn.net/jiwangkailai02/article/details/17015451

使用【格式工廠】進行轉換;

7.通過v4包中的DrawableCompat,通過着色方案完成selector效果
8.使用shape文件替換圖片

9.使用盡量優化的圖片;

10.使用第三方包時把用到的代碼添加到項目中來,避免引用整一個第三方庫。

11.So的使用, 不用兼容所有的cpu架框


七、增量更新(非必須)
1. 背景
window系統的升級過程
android系統的升級過程
android studio的升級過程
國內某些應用升級過程
自從Android 4.1 開始, Google Play 引入了應用程序的增量更新功能,App使用該升級方式,可節省約2/3的流量。
2.什麼是增量更新
升級的時候只需要從服務器下載和本地版本不同的部分,然後在本地在合成新的apk包,也就是只需要升級增加的部分
3.增量更新實現流程


服務器生成和管理差異包客戶端下載差異包,並且與舊包全並形成新的安裝包客戶端再安裝新的安裝包
4.增量更新實現工具--bsdiff


bsdiff: 開源的二進制比較工具作用: apk文件的差分、合成網站: http://www.daemonology.net/bsdiff/
5.增量更新優缺點


節省流量,加快更新速度需要生成和管理很多的差異包
7.原理

服務端:用已有的包和最新的包生成差分包,

客戶端: 下載生成的查分包,最後合併校驗,跟新成功

注意:程序不是很大,比如只有2、3M,那麼完全沒有必要使用增量更新,增量更新適用於apk包比較大的情況,比如遊戲客戶端

八、熱修復(非必須)

1. 概念
一種快速、低成本修復產品軟件版本缺陷的方式;不用重新發包, 在用戶不知情的情況下修復bug

2. 熱修復框架及對比
阿里巴巴:AndFix和Dexposed
微信開源:Tinker
大衆點評:Nuwa
美團:Robust
阿里的開源項目AndFix和Dexposed,目前dexposed的兼容性較差,只有2.3,4.0~4.4兼容,其他Android版本不兼容或未測試;而andfix則兼容2.3~7.0。

微信tinker: github tinkerAndFix: https://github.com/alibaba/AndFix[阿里]Nuwa: https://github.com/jasonross/Nuwa [個人]HotFix: https://github.com/dodola/HotFix [個人]Dexposed: https://github.com/alibaba/dexposed [阿里]
http://www.cnblogs.com/alibaichuan/p/5863616.html

https://blog.csdn.net/itachi85/article/details/79522200

阿里巴巴的AndFix(即時) 採用了底層替換方案

和微信的Tinker(不即時)  

Instant Run方案  底層替換方案

1. 阿里AndFix
主頁: https://github.com/alibaba/AndFix
集成步驟

創建一個新項目AndroidFixDemo, 添加腳本依賴

compile 'com.alipay.euler:andfix:0.3.1@aar' 
添加權限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
添加添加補丁的代碼:實現在應用啓動時(Application的onCreate方法)加載補丁,實現熱修復:(注意: 後面生成的補丁名字叫out.apatch, 並且要放在sdcard根目錄下)

PatchManager patchManager = new PatchManager(this);
patchManager.init("1.0");
 
// 加載補丁
patchManager.loadPatch();
 
// add patch at runtime
try {
    // 注意: 補丁要放到sdkcard根目錄下,並且名字爲out.apatch
    String patchFileString = Environment.getExternalStorageDirectory()
            .getAbsolutePath() + "/out.apatch";
 
    // 添加新補丁
    patchManager.addPatch(patchFileString);
    Log.d("AndFix", "添加新補丁:" + patchFileString);
 
} catch (Exception e) {
    Log.e("AndFix", "", e);
}
對比兩個apk生成補丁out.apatch(注意apk需要進行簽名,否則會修復失敗): 解壓項目AndFix-master.zip/tools裏的apkpatch-1.0.3.zip, 生成兩個apk(原apk和修復後的apk),再通過apkpatch工具對比兩個apk, 在文件夾patch目錄下生成補丁, 然後把後綴名爲.apatch的文件修改爲out.apatch(補丁名需爲:out.apatch)


語法
apkpatch -f <新apk> -t <舊apk> -o <輸出全路徑> -k <簽名文件> -p <密碼> -a <別名> -e <密碼>
 
# 默認簽名
apkpatch -f app-debug-v2.apk -t app-debug-v1.apk -o C:\Users\Administrator\Desktop\apkpatch-1.0.3\patch -k itheima.jks -p christ -a christ-e christ
安裝運行舊版本;

把補丁out.apatch放到sdcard根目錄下:


# 通過adb命令把out.apatch補丁push到sdcard根目錄
adb push out.apatch /sdcard/
關閉舊版本(要退出當前進程),再打開應用,應用會加載補丁,查看是否熱修復成功。
2.微信Tinker(bugly集成)
bugly: bug捕獲, 集成Tinker的熱修復 

集成指南:https://bugly.qq.com/docs/user-guide/instruction-manual-android-hotfix/?v=20170322165254

1.project下build.gradle添加:

// tinkersupport插件, 其中lastest.release指拉取最新版本,也可以指定明確版本號,例如1.0.4
classpath "com.tencent.bugly:tinker-support:latest.release"
2.module下的build.gradle添加:
android {
    defaultConfig {
        ...
        ndk {
            //設置支持的SO庫架構
            abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
        }
    }
}
 
dependencies {
    ...
 
    // 多dex配置
    compile "com.android.support:multidex:1.0.1"
    // 其中latest.release指代最新版本號,也可以指定明確的版本號,例如2.3.2
    compile 'com.tencent.bugly:crashreport_upgrade:latest.release'
    compile 'com.tencent.bugly:nativecrashreport:latest.release' 
}
3.在模塊下創建tinker-support.gradle,該文件的配置如下:
apply plugin: 'com.tencent.bugly.tinker-support'
 
def bakPath = file("${buildDir}/bakApk/")
 
/**
 * 此處填寫每次構建生成的基準包目錄
 */
def baseApkDir = "app-0208-15-10-00"
 
/**
 * 對於插件各參數的詳細解析請參考
 */
tinkerSupport {
 
    // 開啓tinker-support插件,默認值true
    enable = true
 
    // 指定歸檔目錄,默認值當前module的子目錄tinker
    autoBackupApkDir = "${bakPath}"
 
    // 是否啓用覆蓋tinkerPatch配置功能,默認值false
    // 開啓後tinkerPatch配置不生效,即無需添加tinkerPatch
    overrideTinkerPatchConfiguration = true
 
    // 編譯補丁包時,必需指定基線版本的apk,默認值爲空
    // 如果爲空,則表示不是進行補丁包的編譯
    // @{link tinkerPatch.oldApk }
    baseApk = "${bakPath}/${baseApkDir}/app-release.apk"
 
    // 對應tinker插件applyMapping
    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"
 
    // 對應tinker插件applyResourceMapping
    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"
 
    // 構建基準包和補丁包都要指定不同的tinkerId,並且必須保證唯一性
    tinkerId = "base-1.0.1"
 
    // 構建多渠道補丁時使用
    // buildAllFlavorsDir = "${bakPath}/${baseApkDir}"
 
    // 是否開啓反射Application模式
    enableProxyApplication = false
 
}
 
/**
 * 一般來說,我們無需對下面的參數做任何的修改
 * 對於各參數的詳細介紹請參考:
 * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
 */
tinkerPatch {
    //oldApk ="${bakPath}/${appName}/app-release.apk"
    ignoreWarning = false
    useSign = true
    dex {
        dexMode = "jar"
        pattern = ["classes*.dex"]
        loader = []
    }
    lib {
        pattern = ["lib/*/*.so"]
    }
 
    res {
        pattern = ["res/*", "r/*", "assets/*", "resources.arsc", "AndroidManifest.xml"]
        ignoreChange = []
        largeModSize = 100
    }
 
    packageConfig {
    }
 
    sevenZip {
        zipArtifact = "com.tencent.mm:SevenZip:1.1.10"
    //        path = "/usr/local/bin/7za"
    }
 
    buildConfig {
        keepDexApply = false
        //tinkerId = "1.0.1-base"
        //applyMapping = "${bakPath}/${appName}/app-release-mapping.txt" //  可選,設置mapping文件,建議保持舊apk的proguard混淆方式
        //applyResourceMapping = "${bakPath}/${appName}/app-release-R.txt" // 可選,設置R.txt文件,通過舊apk文件保持ResId的分配
    }
}
4.並在app中的build.gradle文件最後添加:


apply from: 'tinker-support.gradle'
5.創建SampleApplicationLike,並指定appid:


public class SampleApplicationLike extends DefaultApplicationLike {
 
    public static final String TAG = "Tinker.SampleApplicationLike";
 
    public SampleApplicationLike(Application application, int tinkerFlags,
            boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,
            long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }
 
    @Override
    public void onCreate() {
        super.onCreate();
        // 這裏實現SDK初始化,appId替換成你的在Bugly平臺申請的appId
        // 調試時,將第三個參數改爲true
        Bugly.init(getApplication(), "a858252095", false);
    }
 
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        // you must install multiDex whatever tinker is installed!
        MultiDex.install(base);
 
        // 安裝tinker
        // TinkerManager.installTinker(this); 替換成下面Bugly提供的方法
        Beta.installTinker(this);
    }
 
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {
        getApplication().registerActivityLifecycleCallbacks(callbacks);
    }
}
6.創建SampleApplication,注意替換如下的包名:(如果項目中要使用自定義的Application需要繼承此SampleApplication)
public class SampleApplication extends TinkerApplication {
    public SampleApplication() {
        super(ShareConstants.TINKER_ENABLE_ALL, "包名.SampleApplicationLike",
                "com.tencent.tinker.loader.TinkerLoader", false);
    }
}
7.在清單文件中配置SampleApplication

<application
    ...
    android:name=".SampleApplication">
8.配置權限
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <--!危險權限需要動態申請 -->
<uses-permission android:name="android.permission.INTERNET" />
<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_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <--!危險權限需要動態申請 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <--!危險權限需要動態申請 -->
9.配置簽名文件, 生成經過正式簽名的apk
signingConfigs {
    config {
        keyAlias 'christ'
        keyPassword '123456'
        storeFile file('C:/christ01.jks')
        storePassword '123456'
    }
}
release {
    // 使用上面配置的簽名文件
    signingConfig signingConfigs.config
}
 
debug {
 
    // 使用上面配置的簽名文件
    signingConfig signingConfigs.config
}
完整接入流程

打基準包安裝並上報聯網(注:填寫唯一的tinkerId)
對基準包的bug修復(可以是Java代碼變更,資源的變更)
修改基準包路徑、修改補丁包tinkerId、mapping文件路徑(如果開啓了混淆需要配置)、resId文件路徑
執行buildTinkerPatchRelease打Release版本補丁包
選擇app/build/outputs/patch目錄下的補丁包並上傳(注:不要選擇tinkerPatch目錄下的補丁包,不然上傳會有問題)
編輯下發補丁規則,點擊立即下發
殺死進程並重啓基準包,請求補丁策略(SDK會自動下載補丁併合成)
再次重啓基準包,檢驗補丁應用結果
查看頁面,查看激活數據的變化

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章