Flutter 混淆打包以及一些注意事項

混淆Dart代碼

Flutter 1.16.2 以上默認(rèn)支持混淆,不需要特殊設(shè)置,只需要在構(gòu)建命令后面加上

--obfuscate --split-debug-info=/<project-name>/<directory>

具體可看官方文檔:混淆Dart代碼

構(gòu)建發(fā)布包

具體配置請看官方文檔(只有很少的配置,很簡單):生成并發(fā)布Android應(yīng)用 、 生成并發(fā)布iOS應(yīng)用

構(gòu)建命令:

Android:

flutter build apk --obfuscate --split-debug-info=./symbols

Google目前建議Android使用 App Bundle 的發(fā)布格式,構(gòu)建命令如下:

flutter build appbundle --target-platform android-arm,android-arm64,android-x64

有不知道 App Bundle 發(fā)布格式的同學(xué)可以查看官方文檔(中文的): Android App Bundle 簡介

iOS:

flutter build ios --obfuscate --split-debug-info=./symbols

注意:

  1. 如果不想混淆代碼的話,iOS只需要去掉 “--obfuscate --split-debug-info=./symbols” 進行構(gòu)建就可以了,Android 的話單獨去掉 “--obfuscate --split-debug-info=./symbols” 是沒有用的,需要在構(gòu)建命令后面加上 “--no-shrink” 表示不混淆代碼:
    flutter build apk --no-shrink
    
  2. 如果你的程序入口不是“main.dart”,而是像我一樣改成“MyApp.dart”的話,需要在構(gòu)建命令后面加上 “--target=lib/MyApp.dart” 指定程序入口:
    flutter build apk --target=lib/MyApp.dart
    或者
    flutter build ios --target=lib/MyApp.dart
    
  3. 在Android上如果你覺得生成出來的apk包太大,或者覺得只需要適配單獨一種架構(gòu)的手機就可以了,你也可以單獨構(gòu)建一種架構(gòu)的apk包:
    flutter build apk --target=lib/MyApp.dart --no-shrink --split-per-abi
    或者
    flutter build apk --target=lib/MyApp.dart --no-shrink --target-platform android-arm,android-arm64,android-x64 --split-per-abi
    
    此命令會生成三種架構(gòu)單獨的apk包:app-armeabi-v7a-release.apk、app-arm64-v8a-release.apk、app-x86_64-release.apk,大大減少apk包的大小。

問題

  1. 報錯如下:

    Execution failed for task ':app:lintVitalRelease'.
    > Could not resolve all artifacts for configuration ':app:profileRuntimeClasspath'.
       > Failed to transform libs.jar to match attributes {artifactType=processed-jar, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
          > Execution failed for JetifyTransform: 項目\build\app\intermediates\flutter\profile\libs.jar.
             > Transform's input file does not exist: 項目\build\app\intermediates\flutter\profile\libs.jar. (See https://issuetracker.google.com/issues/158753935)
    

    解決辦法是先運行一次 debug 或者 profile 模式:

    // debug
    flutter run 
    和
    // profile
    flutter run --profile 
    

    像上面的報錯的意思是找不到 profile 模式下的 libs.jar 文件,我只需要命令行運行一次 profile 模式就可以了。

  2. 目前發(fā)現(xiàn)且未解決的問題是在混淆之后,應(yīng)用所依賴的第三方pub插件(sqflite、dio等)無法正常使用,具體還需進一步測試確認(rèn)。

    • 2021年1月12日更新:
      使用一個空包對dio和sqflite進行混淆測試,build.gradle 和 proguard-rules.pro 配置如下:
      android {
          ...
          buildTypes {
              release {
                  signingConfig signingConfigs.debug
      
                  minifyEnabled true
                  useProguard true
      
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
              }
          }
      }
      
      #默認(rèn)的proguard-android.txt已經(jīng)增加了Annotation、native、view的setget方法、Activity參數(shù)為view的  方法、Enum枚舉、Parcelable、R,此處不再寫
      #------------------------------------------通用區(qū)域----------------------------------------------------
      #----------------------基本指令------------------------
      -optimizationpasses 5
      -dontusemixedcaseclassnames
      -dontskipnonpubliclibraryclasses
      -dontskipnonpubliclibraryclassmembers
      -dontpreverify
      -verbose
      -printmapping proguardMapping.txt
      -optimizations !code/simplification/cast,!field/*,!class/merging/*
      -keepattributes *Annotation*,InnerClasses
      -keepattributes Signature
      -keepattributes SourceFile,LineNumberTable
      
      #如果引用了v4或者v7包
      -dontwarn android.support.**
      -keep class android.support.** { *; }
      -keep interface android.support.** { *; }
      -keep public class * extends android.support.**
      -dontwarn android.support.**
      
      #如果引用了androidx包
      -keep class com.google.android.material.** {*;}
      -keep class androidx.** {*;}
      -keep public class * extends androidx.**
      -keep interface androidx.** {*;}
      -dontwarn com.google.android.material.**
      -dontnote com.google.android.material.**
      -dontwarn androidx.**
      
      #---------------------默認(rèn)保留-------------------------
      ## 基礎(chǔ)保留 ##
      -keep public class * extends android.app.Fragment
      -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.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 com.android.vending.licensing.ILicensingService
      
      -keep public class * extends android.view.View {
          public <init>(android.content.Context);
          public <init>(android.content.Context, android.util.AttributeSet);
          public <init>(android.content.Context, android.util.AttributeSet, int);
          public void set*(...);
      }
      # 保持自定義控件類不被混淆
      -keepclasseswithmembers class * {
          public <init>(android.content.Context, android.util.AttributeSet);
          public <init>(android.content.Context, android.util.AttributeSet, int);
      }
      #保持自定義控件類不被混淆
      -keepclassmembers class * extends android.app.Activity {
          public void *(android.view.View);
      }
      -keepclassmembers enum * {     # 保持枚舉 enum 類不被混淆
          public static **[] values();
          public static ** valueOf(java.lang.String);
      }
      -keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆
          public static final android.os.Parcelable$Creator *;
      }
      -keep class * implements java.io.Serializable # 保持 Serializable 不被混淆
      #保持 Serializable 不被混淆并且enum 類也不被混淆
      -keepclassmembers class * implements java.io.Serializable {
          static final long serialVersionUID;
          private static final java.io.ObjectStreamField[] serialPersistentFields;
          !static !transient <fields>;
          !private <fields>;
          !private <methods>;
          private void writeObject(java.io.ObjectOutputStream);
          private void readObject(java.io.ObjectInputStream);
          java.lang.Object writeReplace();
          java.lang.Object readResolve();
      }
      #不混淆資源類
      -keepclassmembers class **.R$* {
          public static <fields>;
      }
      # 保持 native 方法不被混淆
      -keepclasseswithmembernames class * {
          native <methods>;
      }
      #EventBus的注解
      -keepclassmembers class * {
          @org.greenrobot.eventbus.Subscribe <methods>;
      }
      #WebView
      -keepclassmembers class * extends android.webkit.WebView {*;}
      -keepclassmembers class * extends android.webkit.WebViewClient {*;}
      -keepclassmembers class * extends android.webkit.WebChromeClient {*;}
      -keepclassmembers class * {
          @android.webkit.JavascriptInterface <methods>;
      }
      
      #-------------------------------------------項目定義區(qū)-------------------------------------------------
      #sqflite
      -keep class com.tekartik.sqflite.** { *; }
      #Flutter Wrapper
      #-dontwarn io.flutter.**
      #-keep class io.flutter.app.** { *; }
      #-keep class io.flutter.plugin.**  { *; }
      #-keep class io.flutter.util.**  { *; }
      #-keep class io.flutter.view.**  { *; }
      #-keep class io.flutter.**  { *; }
      #-keep class io.flutter.plugins.**  { *; }
      
      測試結(jié)果正常,但是發(fā)現(xiàn)混淆對泛型十分不友好,很可能因為泛型導(dǎo)致混淆之后APP不能正常使用,比如我在 Flutter Dio二次封裝 這篇文章里面的那個json轉(zhuǎn)換工廠 EntityFactory:
      class EntityFactory {
        static T generateOBJ<T>(json) {
          if (json == null) {
            return null;
          }
          else if (T.toString() == "LoginEntity") {
            return LoginEntity.fromJson(json) as T;
          }
          else {
            return json as T;
          }
        }
      }
      
      這里需要使用 T.toString() == "LoginEntity" 對泛型進行具體的判斷,但是混淆之后泛型 T 傳進來的是混淆之后的符號,所以導(dǎo)致 T.toString() == "LoginEntity" 判斷失敗無法使用具體的實體去解析 json,我想下一步需要找辦法配置對某些文件進行混淆排除。。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容