安卓轉戰React-Native之簽名打包成Apk並極速多渠道打包

前言

搞安卓的開發應該知道開發好的apk都是需要上傳到應用市場給用戶下載的,當然有些公司的產品是不用上傳到應用市場的(比如我們公司放七牛雲)但是也需要放在雲上面給用戶下載。react-native直接run-android默認是產生一個debug的版本apk顯然這是不符合開發需求的,理由很簡單debug版本apk是沒有進行代碼混淆的這是很危險的,所以我們需要個release的版本,下面我們來詳細看一下怎麼樣進行簽名打包React Native應用並且多渠道打包。

debug和release版本apk反編譯後比較

準備工具

先下載反編譯工具包:dex2jar-2.0jd-guiapktool

反編譯

先把apk解壓獲取classes.dex,再獲得classes-dex2jar.jar

使用jd-gui查看源代碼(debug版本效果)

當然這裏只是helloword做個例子,並沒有寫什麼代碼即使混淆了也看不出什麼效果(因爲第三方的包都不能混淆),但是混淆後效果還是好點:看下其他的例子(直接偷郭霖的圖):(release版本效果)

Android簽名文件生成

Android簽名文件包含2種格式:.keystore和.jks

安卓簽名文件的生成不外乎2種方式:我現在給大家講解兩種簽名生成的方法:①:keytool命令方式生成 ,②:Android Studio IDE和Eclipse IDE進行生成。

  • keytool命令生成keystore文件(如果沒有安裝androidStudio或eclispe)

以前我也有寫過用藍貝兒多渠道打包裏面介紹了使用自帶的keytool命令生成簽名文件,這裏再來介紹一下

keytool -genkey -v -keystore losileeya.keystore -alias losileeya(別名) -keyalg RSA(算法) -keysize 2048(密鑰長度) -validity 10000(有效期,天單位)

個人比較傾向於使用ide這一種方法,首先是圖形界面的,而且少了命令行書寫的問題,而且以前我記得在使用Eclipse開發Android的時候也一直使用這種方式,下面我們來看一下生成簽名的具體步驟:

  • IDE 工具生成簽名文件

    1.Android Studio IDE生成jks文件

    build—>Generate Signed apk

    接下來:

    2.Eclipse IDE生成keystore文件

Gradle配置

(1)把剛纔生成的.jks文件考入到項目android/app文件夾下面

(2)直接在工程目錄下得android/app/build.gradle中以下節點添加如下內容:
方法一:gradle的全局配置:
修改項目中gradle.properties文件

MYAPP_RELEASE_STORE_FILE=losileeya.jks
MYAPP_RELEASE_KEY_ALIAS=losileeya
MYAPP_RELEASE_STORE_PASSWORD=losileeya
MYAPP_RELEASE_KEY_PASSWORD=losileeya

直接在工程目錄下得android/app/build.gradle中以下節點添加如下內容:

 signingConfigs {
        release {
            storeFile file(MYAPP_RELEASE_STORE_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }

方法二:gradle的局部配置:

  signingConfigs {
        release {
            storeFile file("C://Users/Administrator/ZyReact/android/app/losileeya.jks")//這裏可以寫絕對位置或者相對位置
            storePassword "losileeya"
            keyAlias "losileeya"
            keyPassword "losileeya"
        }
    }
    buildTypes {
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            signingConfig signingConfigs.release
        }
    }

看圖:
這裏寫圖片描述
記得把enableProguardInReleaseBuilds改爲true,最好把enableSeparateBuildPerCPUArchitecture = true,然後各種簽名參數的值都不能錯否則打包失敗,基本上build.gradle的配置也就這些了。當然代碼混淆文件proguard-rules.pro自己配置。
例如我上個項目:

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
# 指定代碼的壓縮級別0~7
-optimizationpasses 5  
# 是否使用大小寫混合                                                   
-dontusemixedcaseclassnames    
# 是否混淆第三方jar                                                  
-dontskipnonpubliclibraryclasses    
# 混淆時是否做預校驗                                           
-dontpreverify 
#重命名
-renamesourcefileattribute SourceFile
#保護給定的可選屬性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.                                                                  
-keepattributes SourceFile,LineNumberTable      
# 混淆時是否記錄日誌                            
-verbose                                                                        
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*      
##壓縮 
 #不壓縮輸入的類文件 
-dontshrink   
##優化 
#不優化輸入的類文件 
-dontoptimize    
#優化時允許訪問並修改有修飾符的類和類的成員 
-allowaccessmodification     
#混淆庫
-libraryjars libs/volley.jar
-libraryjars libs/android-support-v4.jar
-libraryjars libs/gson-2.3.1.jar
-libraryjars libs/locSDK_6.13.jar
-libraryjars libs/zxing-core-3.1.0.jar
#-libraryjars libs/MarsorUtils-1.0.0-SNAPSHOT.jar
-libraryjars libs/dom4j-2.0.0-RC1.jar
-libraryjars libs/mta-sdk-1.6.2.jar
-libraryjars libs/open_sdk_r5509.jar
-libraryjars libs/libammsdk.jar
-libraryjars libs/WeiboSDKCore_3.1.2.jar
-libraryjars libs/alipaySDK-20150724.jar
-libraryjars libs/CMISUBTSwiper_sdk_v1.3.jar
-libraryjars libs/CMSETSwiper_SDK_V3.6.jar
-libraryjars libs/dspread_android_sdk_2.4.6.jar
-libraryjars libs/message_lib.jar
-libraryjars libs/meSdk-1.1.7snapshot_ruiyin.jar
-libraryjars libs/disklrucache-2.0.1.jar
-libraryjars libs/httpclient-4.2.5.jar
-libraryjars libs/httpcore-4.2.4.jar
-libraryjars libs/universal-image-loader-1.9.5.jar
-keepattributes *Annotation*
-keep class android.** {*; }
-keep public class * extends android.view  
-keep public class * extends android.app.Activity                             
-keep public class * extends android.app.Application                            
-keep public class * extends android.app.Service 
-keep public class * extends android.content.pm                                
-keep public class * extends android.content.BroadcastReceiver                
-keep public class * extends android.content.ContentProvider                  
-keep public class * extends android.app.backup.BackupAgentHelper              
-keep public class * extends android.preference.Preference  
-keep public class * extends android.app.Fragment  
-keep public class com.android.vending.licensing.ILicensingService            
-keep class android.support.v4.app.** { *; }
-keep class android.support.v7.** { *; }
-keep class com.google.gson.** { *; }
-keep class com.baidu.mapapi.** { *; }
-keep class com.baidu.platform.** { *; }
-keep class com.baidu.vi.** { *; }
-keep class com.baidu.location.** { *; }
-keep class org.apache.http.** { *; }
-keep class org.json.** { *; }
-keep class com.nostra13.universalimageloader.** { *; }
# keep 所有的 javabean
-keep class com.richerpay.ryshop.bean.** { *; }
# volley
# # -------------------------------------------
# #  ############### volley混淆  ############### 
# # -------------------------------------------
-keep class com.android.volley.** {*;}
-keep class com.android.volley.toolbox.** {*;}
-keep class com.android.volley.Response$* { *; }
-keep class com.android.volley.Request$* { *; }
-keep class com.android.volley.RequestQueue$* { *; }
-keep class com.android.volley.toolbox.HurlStack$* { *; }
-keep class com.android.volley.toolbox.ImageLoader$* { *; }
-keep class org.dom4j.** { *; }
-keep class android.support.annotation.** { *; }
-keep class com.tencent.mm.sdk.** {*;}
-keep class com.tencent.tauth.** {*;}
-keep class com.tencent.open.TDialog$*
-keep class com.tencent.open.TDialog$* {*;}
-keep class com.tencent.open.PKDialog
-keep class com.tencent.open.PKDialog {*;}
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
-keep class com.misu.btswiper.**{*;}
-keep class com.shxy.cardswiper.**{*;}
-keep class com.dspread.xpos.QPOSService.**{*;}
-keep class com.bypay.swiper.**{*;}
-keep class com.newland.ruiyin.**{*;}
# 保持自己定義的類不被混淆
-keep class com.richerpay.ryshop.view.**{*;}
-keep class com.richerpay.ryshop.volly.**{*;}
-keep class com.richerpay.ryshop.widget.**{*;}
-dontwarn org.apache.http.**
-keepclassmembers class * {
   public <init>(org.json.JSONObject);
}
-keep public class com.hrbcb.studentloans.R$*{
public static final int *;
}
# 微信
-keep class com.tencent.mm.sdk.openapi.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.openapi.** implements com.tencent.mm.sdk.openapi.WXMediaMessage$IMediaObject {*;}
# 新浪微博
-keep class com.sina.**{*;}
#枚舉不被混淆
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
# 保持自定義控件類不被混淆
-keepclasseswithmembers class * {                                               
    public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);     
}
#點擊事件不被混淆
-keepclasseswithmembers class * {
    void onClick*(...);
}
#回調
-keepclasseswithmembers class * {
    *** *Callback(...);
}
#get 和set
-keepclassmembers public class * extends android.view.View {
   void set*(***);
   *** get*();
}

#本地方法
-keepclasseswithmembernames class * {
    native <methods>;
}
# activity
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}
#實現Parcelable 接口的不被混淆
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
#R文件屬性不被混淆
-keepclassmembers class **.R$* {
    public static <fields>;
}

#缺省proguard 會檢查每一個引用是否正確,但是第三方庫裏面往往有些不會用到的類,沒有正確引用。如果不配置的話,系統就會報錯。
-dontwarn android.support.**
# 實現Serializable 接口的不被混淆
-keepnames class * implements java.io.Serializable  
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
    public <fields>;
}

#dom4j不被混淆
-keepclassmembers class org.dom4j.** {*;}
#百度定位
-keepclassmembers class com.baidu.location.** {*;}
-keepattributes Signature

# Gson混淆
## ----------------------------------
##   ########## Gson混淆    ##########
## ----------------------------------
-keepclassmembers class com.google.gson.** {*;}
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.gson.examples.android.model.** { *; }
# Application classes that will be serialized/deserialized over Gson

##---------------End: proguard configuration for Gson  ----------
-ignorewarnings 
-dontwarn org.xmlpull.v1.XmlSerializer 
-keepattributes Signature  

這個只是規則可以參考下,畢竟react-native沒有什麼activity這寫東西,如果你對這個還是不瞭解,可以去看郭神的反編譯與混淆技術完全解析(下)

打包文件的生成2種方式

對存在react.gradle文件的項目打包

命令很簡單:

cd android && ./gradle assembleRelease

這裏寫圖片描述
網速渣的一逼:5min
這裏寫圖片描述

不存在react.gradle文件的項目打包

對不存在react.gradle文件那麼我們就需要生成assets文件夾,並且生成index.android.bundle文件

方法一:利用curl生成
命令如下:

cd ZyReact(定位到你的工程根目錄)
curl -k "http//localhost:8081/index.android.bundle" >android/app/src/main/assets/index.android.bundle

如圖:
這裏寫圖片描述
這裏使用的curl.exe要自己去下載,記得需要開啓服務。生成成功後如下:
這裏寫圖片描述
方法二:
首先命令切換到該react native項目的主目錄,然後運行以下的命令,生成assets文件夾

mkdir -p android/app/src/main/assets

緊接着運行以下命令,進行生成index.android.bundle文件

react-native bundle --platform android --dev false --entry-file index.android.js \
  --bundle-output android/app/src/main/assets/index.android.bundle \
  --assets-dest android/app/src/main/res/

總之不管哪種方法打包都要執行

cd android && ./gradle assembleRelease

下面我們來看一下release包的效果:
這裏寫圖片描述

安裝apk

上面的步驟我們已經完成了項目的簽名打包在對應的目錄中生成中apk文件,下面我們直接運行以下的命令進行將apk安裝到設備中。

cd android && ./gradle installRelease

看圖:
這裏寫圖片描述

美團多渠道極速打包

爲什麼要進行多渠道打包?

不搞安卓開發的或許不知道什麼是多渠道打包,ios呢也就一般放appstore裏面,然而打包安卓應用商店(一個商店也叫做一個渠道,如360,baidu,xiaomi,應用寶)衆多,大大小小几百個,我們發佈應用之後需要統計各個渠道的用戶下載量,所以纔有了多渠道打包。

怎麼樣統計各個渠道的下載量呢?

現在有比較成熟的第三方應用幫我們實現統計功能(比如友盟),統計的本質就是收集用戶信息傳輸到後臺,後臺生成報表,幫助我們跟蹤分析並完善app。通過系統的方法已經可以獲取到,版本號,版本名稱,系統版本,機型,地區等各種信息,唯獨應用商店(渠道)的信息我們是沒有辦法從系統獲取到的,所以我們就人爲的在apk裏面添加渠道信息(其實就用一個字段進行標識,如360,baidu),我們只要把這些信息打包到apk文件並將信息傳輸到後臺,後臺根據這個標識,可以統計各個渠道的下載量了,並沒有多麼的高大上。
說了那麼多,其實多渠道打包只需要關注兩件事情:

1.將渠道信息寫入apk文件

2.將apk中的渠道信息傳輸到統計後臺

常見的多渠道打包方法有哪些?

1.插件打包法
2.Android的productFlavors打包法

以前我也寫過多渠道比如藍貝殼多渠道(插件打包法)打包,但是呢速度還是比較慢,然後也寫過android studio的多渠道打包(Android的productFlavors打包法)需要手動去配置然後速度也不是很快,然後美團的打包方式以快著稱,哈哈。

下面帶你輕鬆搞定美團多渠道打包

  • 下載安裝python環境 Python下載地址

  • 下載python腳本 AndroidMultiChannelBuildTool

  • 將ChannelUtil.java代碼集成到工程裏面,在app啓動時獲取渠道號傳送給後臺(如友盟:AnalyticsConfig.setChannel(ChannelUtil.getChannel(this));
  • 在PythonTool/Info/channel.txt中編輯渠道列表,以換行隔開,工程中有示例
  • 打包apk,將apk文件複製到PythonTool目錄下(與py同級),運行(直接雙擊.py文件或者在命令行輸入 python MultiChannelBuildTool.py )py腳本即可打包完成。(生成的渠道apk包在output_** 目錄下)

由於我們配置環境的時候下載安裝了python ,只需下載AndroidMultiChannelBuildTool壓縮包解壓後是這樣的:
這裏寫圖片描述
把簽好名的apk放到py同級目錄下,點擊不到10秒鐘就生成output文件夾並且下面生成了多個渠道包:
這裏寫圖片描述

總結

時間不早了就寫到這裏,打包的知識又複習了一遍,寫個博客各種截圖也是相當的累,其實打包React-Native沒有幾句代碼。

  • 生成自己的簽名文件 (.jks或。keystore)
  • 配置gradle文件
  • 寫代碼混文件
  • 有必要的話生成assets文件夾,並且寫入index.android.bundle
  • gradle assembleRelease執行打包命令
  • 有需求的話多渠道打包

好了,做任何一件事都不是簡單,唯有自己熟悉做起來才快,好好學習好好生活吧。

come on,enjoy it

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