标签: Flutter

  • Flutter中的IoC

    因为长期做后端开发,Spring提供的IoC功能确实用的很多。到了Flutter中各种依赖项目的管理也很麻烦,也影响单元测试的编写。

    所以在Flutter还是希望延续平时的习惯,使用IoC去控制依赖等关系。但是Flutter中有一些特殊的情况,比如Flutter禁用了dart:mirrors,反射的使用上有一些问题。对比了几个框架,最开始考虑的是Google下面的inject.dart,但是文档这块比较缺,还有就是注解+代码生成的方式强大,但是不是很喜欢,也用不了这么强的功能。由于名字的原因也看了下ioc库(https://pub.dev/packages/ioc),对于API的语法不是很喜欢。最后选择使用GetIt。

    使用上比较简单,引用依赖

    dependencies:
      get_it: ^3.1.0

    代码中专门配置一个方法用于管理所有依赖配置

    class IocConfiguration {
      configDependencies(
          {AnalysisService analysisService}) {
        var loader = GetIt.I;
    
        loader
            .registerLazySingleton<LoggingService>((() => SimpleLoggingService()));
    
        if (analysisService != null) {
          loader.registerLazySingleton<AnalysisService>((() => analysisService));
        } else {
          loader.registerLazySingleton<AnalysisService>(
              (() => FirebaseAnalysisService()));
        }
    
        loader.registerLazySingleton<HttpService>((() => DioHttpService(
            loader.get<AnalysisService>(), loader.get<LoggingService>())));
    
        return loader;
      }
    }

    由于这个方法启动时会调用,所以所有依赖都是配置的懒加载,而各种Service都是用构造器设置依赖。

    同时留了个口子,对于单元测试需要替换的/需要Mock的对象可以在配置时额外传入。这一块以后怎么管理还没有想好,目前还够用。

    总的来说因为反射的缺失,这块还是满不方便,类似的还有json序列化和反序列化。

    参考

    https://github.com/google/inject.dart#can-i-use-this-with-flutter

    https://pub.dev/packages/get_it

  • Flutter打包后闪退问题

    最近在搞Flutter,在模拟器调试一切正常,但是flutter build apk以后真机闪退,看了下日志,报错如下:

    E/flutter ( 5319): [ERROR:flutter/shell/platform/android/platform_view_android_jni.cc(39)] java.lang.NoClassDefFoundError: g.a.b.o3
    E/flutter ( 5319): 	at g.a.b.r.v(Unknown Source:0)
    E/flutter ( 5319): 	at com.huangyunkun.kiwi.a.a(Unknown Source:102)
    E/flutter ( 5319): 	at com.huangyunkun.kiwi.MainActivity$a.a(Unknown Source:153)
    E/flutter ( 5319): 	at c.a.c.a.j$a.a(Unknown Source:17)
    E/flutter ( 5319): 	at io.flutter.embedding.engine.e.b.a(Unknown Source:57)
    E/flutter ( 5319): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(Unknown Source:4)
    E/flutter ( 5319): 	at android.os.MessageQueue.nativePollOnce(Native Method)
    E/flutter ( 5319): 	at android.os.MessageQueue.next(MessageQueue.java:326)
    E/flutter ( 5319): 	at android.os.Looper.loop(Looper.java:165)
    E/flutter ( 5319): 	at android.app.ActivityThread.main(ActivityThread.java:6815)
    E/flutter ( 5319): 	at java.lang.reflect.Method.invoke(Native Method)
    E/flutter ( 5319): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    E/flutter ( 5319): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
    E/flutter ( 5319): Caused by: java.lang.ExceptionInInitializerError
    E/flutter ( 5319): 	at g.a.b.r.a(Unknown Source:0)
    E/flutter ( 5319): 	at g.a.b.r.a(Unknown Source:4)
    E/flutter ( 5319): 	at g.a.b.r.u(Unknown Source:1)
    E/flutter ( 5319): 	at com.huangyunkun.kiwi.a.a(Unknown Source:15)
    E/flutter ( 5319): 	... 11 more
    E/flutter ( 5319): Caused by: java.lang.IllegalStateException: Failed to create VMBridge instance
    E/flutter ( 5319): 	at g.a.b.o3.b(Unknown Source:40)
    E/flutter ( 5319): 	at g.a.b.o3.<clinit>(Unknown Source:0)
    E/flutter ( 5319): 	... 15 more
    E/flutter ( 5319): 
    F/flutter ( 5319): [FATAL:flutter/shell/platform/android/platform_view_android_jni.cc(76)] Check failed: CheckException(env). 

    看java.lang.NoClassDefFoundError: g.a.b.o3应该是android的混淆没对,但是找了一圈proguard却找不到。

    查看下文档发现现在已经用R8了,不过默认还是兼容proguard rule的,那么首先先把日志输出看下。

    默认配置是

    # This is a configuration file for ProGuard.
    # http://proguard.sourceforge.net/index.html#manual/usage.html
    #
    # Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
    # the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
    # will be ignored by new version of the Android plugin for Gradle.
    
    # Optimization is turned off by default. Dex does not like code run
    # through the ProGuard optimize steps (and performs some
    # of these optimizations on its own).
    # Note that if you want to enable optimization, you cannot just
    # include optimization flags in your own project configuration file;
    # instead you will need to point to the
    # "proguard-android-optimize.txt" file instead of this one from your
    # project.properties file.
    -dontoptimize
    
    -dontusemixedcaseclassnames
    -dontskipnonpubliclibraryclasses
    -verbose
    
    # Preserve some attributes that may be required for reflection.
    -keepattributes *Annotation*,Signature,InnerClasses,EnclosingMethod
    
    -keep public class com.google.vending.licensing.ILicensingService
    -keep public class com.android.vending.licensing.ILicensingService
    -keep public class com.google.android.vending.licensing.ILicensingService
    -dontnote com.android.vending.licensing.ILicensingService
    -dontnote com.google.vending.licensing.ILicensingService
    -dontnote com.google.android.vending.licensing.ILicensingService
    
    # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    # Keep setters in Views so that animations can still work.
    -keepclassmembers public class * extends android.view.View {
        void set*(***);
        *** get*();
    }
    
    # We want to keep methods in Activity that could be used in the XML attribute onClick.
    -keepclassmembers class * extends android.app.Activity {
        public void *(android.view.View);
    }
    
    # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    -keepclassmembers class * implements android.os.Parcelable {
        public static final ** CREATOR;
    }
    
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    # Preserve annotated Javascript interface methods.
    -keepclassmembers class * {
        @android.webkit.JavascriptInterface <methods>;
    }
    
    # The support libraries contains references to newer platform versions.
    # Don't warn about those in case this app is linking against an older
    # platform version. We know about them, and they are safe.
    -dontnote android.support.**
    -dontnote androidx.**
    -dontwarn android.support.**
    -dontwarn androidx.**
    
    # This class is deprecated, but remains for backward compatibility.
    -dontwarn android.util.FloatMath
    
    # Understand the @Keep support annotation.
    -keep class android.support.annotation.Keep
    -keep class androidx.annotation.Keep
    
    -keep @android.support.annotation.Keep class * {*;}
    -keep @androidx.annotation.Keep class * {*;}
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <methods>;
    }
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <methods>;
    }
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <fields>;
    }
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <fields>;
    }
    
    -keepclasseswithmembers class * {
        @android.support.annotation.Keep <init>(...);
    }
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <init>(...);
    }
    
    # These classes are duplicated between android.jar and org.apache.http.legacy.jar.
    -dontnote org.apache.http.**
    -dontnote android.net.http.**
    
    # These classes are duplicated between android.jar and core-lambda-stubs.jar.
    -dontnote java.lang.invoke.**
    
    # Build the ephemeral app in a module project.
    # Prevents: Warning: library class <plugin-package> depends on program class io.flutter.plugin.**
    # This is due to plugins (libraries) depending on the embedding (the program jar)
    -dontwarn io.flutter.plugin.**
    
    # The android.** package is provided by the OS at runtime.
    -dontwarn android.**
    
    -printconfiguration full-r8-config.txt
    
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:25
    -keep class androidx.core.app.CoreComponentFactory { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:126
    -keep class com.google.android.gms.common.api.GoogleApiActivity { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:97
    -keep class com.google.android.gms.measurement.AppMeasurementInstallReferrerReceiver { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:111
    -keep class com.google.android.gms.measurement.AppMeasurementJobService { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:92
    -keep class com.google.android.gms.measurement.AppMeasurementReceiver { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:107
    -keep class com.google.android.gms.measurement.AppMeasurementService { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:51
    -keep class com.google.firebase.components.ComponentDiscoveryService { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:117
    -keep class com.google.firebase.iid.FirebaseInstanceIdReceiver { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:81
    -keep class com.google.firebase.perf.provider.FirebasePerfProvider { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:131
    -keep class com.google.firebase.provider.FirebaseInitProvider { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:30
    -keep class com.huangyunkun.kiwi.MainActivity { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:25
    -keep class io.flutter.app.FlutterApplication { <init>(); }
    # Referenced at /Users/huangyunkun/OpenSource/kiwi/build/app/intermediates/merged_manifests/release/AndroidManifest.xml:87
    -keep class io.flutter.plugins.urllauncher.WebViewActivity { <init>(); }
    
    # Needed when app is not using OkHttp
    -dontwarn okio.**
    
    # Needed when app's compileSdkVersion < 24
    -dontwarn com.google.firebase.perf.network.**
    
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.firebase-perf.zzep {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.clearcut.zzcg {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.firebase_remote_config.zzhi {
      <fields>;
    }
    
    # Auto-generated proguard rule with obfuscated symbol
    -keepclassmembers class * {
      @com.google.android.gms.internal.firebase_remote_config.zzcc <fields>;
    }
    
    
    # b/35135904 Ensure that proguard will not strip the mResultGuardian.
    -keepclassmembers class com.google.android.gms.common.api.internal.BasePendingResult {
      com.google.android.gms.common.api.internal.BasePendingResult$ReleasableResultGuardian mResultGuardian;
    }
    
    -dontwarn com.google.firebase.platforminfo.KotlinDetector
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # We keep all fields for every generated proto file as the runtime uses
    # reflection over them that ProGuard cannot detect. Without this keep
    # rule, fields may be removed that would cause runtime failures.
    -keepclassmembers class * extends com.google.android.gms.internal.measurement.zzfd {
      <fields>;
    }
    
    # Proguard flags for consumers of the Google Play services SDK
    # https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project
    
    # Keep SafeParcelable NULL value, needed for reflection by DowngradeableSafeParcel
    -keepclassmembers public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
        public static final *** NULL;
    }
    
    # Needed for Parcelable/SafeParcelable classes & their creators to not get renamed, as they are
    # found via reflection.
    -keep class com.google.android.gms.common.internal.ReflectedParcelable
    -keepnames class * implements com.google.android.gms.common.internal.ReflectedParcelable
    -keepclassmembers class * implements android.os.Parcelable {
      public static final *** CREATOR;
    }
    
    # Keep the classes/members we need for client functionality.
    -keep @interface androidx.annotation.Keep
    -keep @androidx.annotation.Keep class *
    -keepclasseswithmembers class * {
      @androidx.annotation.Keep <fields>;
    }
    -keepclasseswithmembers class * {
      @androidx.annotation.Keep <methods>;
    }
    
    # Keep the names of classes/members we need for client functionality.
    -keep @interface com.google.android.gms.common.annotation.KeepName
    -keepnames @com.google.android.gms.common.annotation.KeepName class *
    -keepclassmembernames class * {
      @com.google.android.gms.common.annotation.KeepName *;
    }
    
    # Keep Dynamite API entry points
    -keep @interface com.google.android.gms.common.util.DynamiteApi
    -keep @com.google.android.gms.common.util.DynamiteApi public class * {
      public <fields>;
      public <methods>;
    }
    
    # Needed when building against pre-Marshmallow SDK.
    -dontwarn android.security.NetworkSecurityPolicy
    
    # Needed when building against Marshmallow SDK.
    -dontwarn android.app.Notification
    
    # Protobuf has references not on the Android boot classpath
    -dontwarn sun.misc.Unsafe
    -dontwarn libcore.io.Memory
    
    # Internal Google annotations for generating Proguard keep rules.
    -dontwarn com.google.android.apps.common.proguard.UsedBy*
    
    # Annotations referenced by the SDK but whose definitions are contained in
    # non-required dependencies.
    -dontwarn javax.annotation.**
    -dontwarn org.checkerframework.**
    # Copyright 2018 The Chromium Authors. All rights reserved.
    # Use of this source code is governed by a BSD-style license that can be
    # found in the LICENSE file.
    
    # We need to avoid obfuscating the support library boundary interface because
    # this API is shared with the Android Support Library.
    # Note that we only 'keep' the package org.chromium.support_lib_boundary itself,
    # any sub-packages of that package can still be obfuscated.
    -keep public class org.chromium.support_lib_boundary.* { public *; }
    
    # Copyright (C) 2018 The Android Open Source Project
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    # Prevent WebViewClientCompat from being renamed, since chromium depends on this name.
    -keepnames public class androidx.webkit.WebViewClientCompat
    
    
    # Copyright (C) 2016 The Android Open Source Project
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    # CoordinatorLayout resolves the behaviors of its child components with reflection.
    -keep public class * extends androidx.coordinatorlayout.widget.CoordinatorLayout$Behavior {
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>();
    }
    
    # Make sure we keep annotations for CoordinatorLayout's DefaultBehavior and ViewPager's DecorView
    -keepattributes *Annotation*
    
    # aapt2 is not (yet) keeping FQCNs defined in the appComponentFactory <application> attribute
    -keep class androidx.core.app.CoreComponentFactory
    
    # JSR 305 annotations are for embedding nullability information.
    -dontwarn javax.annotation.**
    
    # A resource is loaded with a relative path so the package of this class must be preserved.
    -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
    
    # Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
    -dontwarn org.codehaus.mojo.animal_sniffer.*
    
    # OkHttp platform used only on JVM and when Conscrypt dependency is available.
    -dontwarn okhttp3.internal.platform.ConscryptPlatform
    
    -keepattributes *Annotation*
    
    -keepclassmembers enum androidx.lifecycle.Lifecycle$Event {
        <fields>;
    }
    
    -keep !interface * implements androidx.lifecycle.LifecycleObserver {
    }
    
    -keep class * implements androidx.lifecycle.GeneratedAdapter {
        <init>(...);
    }
    
    -keepclassmembers class ** {
        @androidx.lifecycle.OnLifecycleEvent *;
    }
    -keep public class * extends androidx.versionedparcelable.VersionedParcelable
    -keep public class android.support.**Parcelizer { *; }
    -keep public class androidx.**Parcelizer { *; }
    -keep public class androidx.versionedparcelable.ParcelImpl
    
    -dontwarn com.google.firebase.components.Component$Instantiation
    -dontwarn com.google.firebase.components.Component$ComponentType
    -keep class * implements com.google.firebase.components.ComponentRegistrar
    
    -keepclassmembers,allowobfuscation class * extends androidx.lifecycle.ViewModel {
        <init>();
    }
    
    -keepclassmembers,allowobfuscation class * extends androidx.lifecycle.AndroidViewModel {
        <init>(android.app.Application);
    }
    
    -keep,allowobfuscation @interface androidx.annotation.Keep
    -keep @androidx.annotation.Keep class * {*;}
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <methods>;
    }
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <fields>;
    }
    
    -keepclasseswithmembers class * {
        @androidx.annotation.Keep <init>(...);
    }
    
    -ignorewarnings

    因为唯一和原生有关的就是自定义了一个rhino的channel,直接keep即可

    -keep class org.mozilla.javascript.** { *; }

    如果是开发阶段也可以先关闭混淆,后面统一处理

    android.enableR8=false

    参考

    https://developer.android.com/studio/build/shrink-code#troubleshoot

    https://developer.android.com/studio/build/shrink-code#configuration-files