Confusing the Dart code

Flutter 1.16.2 supports obfuscation by default. No special Settings are required, just add it at the end of the build command

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

See the official documentation for details: Confusing the Dart code

Build distribution packages

See the official documentation for the configuration (there are only a few, very simple configurations) : Build and publish Android apps, build and publish iOS apps

Build command:

Android:

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

Google currently recommends that Android use the App Bundle distribution format, with the following build commands:

flutter build appbundle --target-platform android-arm,android-arm64,android-x64
Copy the code

For those of you who do not know the format of the App Bundle, please refer to the official document: Introduction to Android App Bundle

IOS:

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

Note:

  1. If you don’t want to confuse the code, iOS just needs to build without “–obfuscate –split-debug-info=./symbols”. It is useless for Android to remove the “–obfuscate –split-debug-info=./symbols” separately. It is necessary to add “–no-shrink” after the build command to avoid obfuscate code:
    flutter build apk --no-shrink
    Copy the code
  2. Dart –target=lib/ myapp.dart if your program entry is not “main.dart” but “myapp.dart” as I did, you need to specify the program entry by adding “–target=lib/ myapp.dart” to the end of the build command:
    Dart or build ios --target=lib/ myapp.dartCopy the code
  3. On Android, if you think the generated APK package is too big, or if you just need to fit a phone with a separate architecture, you can also build a separate architecture apK package:
    Dart --no-shrink --split-per-abi or build apk --target=lib/ myapp.dart --no-shrink --target-platform android-arm,android-arm64,android-x64 --split-per-abiCopy the code

    This command generates three separate APK packages: app-armeabi-v7a-release.apk, app-arm64-v8a-release.apk, and app-x86_64-release.apk, greatly reducing the size of the APK package.

The problem

  1. Error as follows:

    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: Project \build\app\intermediates\flutter\profile\libs.jar. > Transform's input file does not exist: Project, build \ app \ intermediates, flutter \ profiles \ libs jar. (See https://issuetracker.google.com/issues/158753935)Copy the code

    The solution is to run debug or profile mode first:

    Debug flutter run and // profile flutter run --profileCopy the code

    The libs.jar file in profile mode cannot be found. I only need to run profile mode once.

  2. At present, the unsolved problem is that the third-party PUB plug-in (SQflite, Dio, etc.) on which the application relies cannot be used normally after the confusion, which needs further testing and confirmation.

    • Updated January 12, 2021:

      Use an empty package to confound dio and SQflite, build.gradle and ProGuard-rules.pro configured as follows:

      android {
          ...
          buildTypes {
              release {
                  signingConfig signingConfigs.debug
      
                  minifyEnabled true
                  useProguard true
      
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
              }
          }
      }
      Copy the code
      The default proguard-android. TXT file has been added with Annotation, native, setget method of view, Activity method of view, Enum, Parcelable, R, etc. Here no longer write # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- general area -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- basic instructions -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 5 - dontusemixedcaseclassnames optimizationpasses -dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclassmembers -dontpreverify -verbose -printmapping proguardMapping.txt -optimizations ! code/simplification/cast,! field/*,! class/merging/* -keepattributes *Annotation*,InnerClasses -keepattributes Signature -keepattributes SourceFile, LineNumberTable # if quotes or v4 v7 - dontwarn android. Support. * * - keep class android. Support. {* * *; } -keep interface android.support.** { *; } -keep public class * extends android.support.** -dontwarn android.support.** # 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.** # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the default reserves -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- based retain # # # # - keep public class * extends. Android app. The fragments - 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*(...) ; } # maintain custom control class not be confused - keepclasseswithmembers class * {public < init > (android. The content. The Context, android. Util. AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); } # keep custom control classes from being confused - keepClassMembers class extends Android.app.activity {public void *(android.view.view); } -keepClassMembers enum * {public static **[] values(); public static ** valueOf(java.lang.String); } - implements android.os.Parcelable {# implements android.os.Parcelable public static final android.os.Parcelable$Creator *; } - class * implements java.io.Serializable # implements java.io.Serializable # implements java.io -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>; } # keep native method is not be confused - keepclasseswithmembernames class * {native < the methods >; {} # EventBus annotations - keepclassmembers class * @ org. Greenrobot. EventBus. Subscribe < the 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>; } # -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- project definition area -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- # 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.** { *; }Copy the code

      The result of the test was normal, but it was found that the confusion was very unfriendly to generics. It is likely that the APP could not be used normally after the confusion caused by generics. For example, I re-wrapped the JSON conversion factory EntityFactory in this article on Flutter Dio:

      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; }}}Copy the code

      Here we need to use t.tostring () == “LoginEntity” to make a specific judgment about the generic, but after the obfuscation the generic T passes in the obfuscation symbol, As a result, t.tostring () == “LoginEntity” failed to judge and could not parse JSON with a specific entity. I think the next step is to find a way to configure obfuscation exclusion for some files.