• Android-Firebase快速解决合规问题第4篇,解决FirebaseAnalytics库违规获取应用列表问题


    系列文章

    背景

    2022年9月,小米应用商店上架审核,提示存在违规行为。
    违规行为:未经许可读取个人信息 | 获取应用列表

    依赖环境

    demo的环境如下,只是为了演示firebase出现的问题,本篇文章基于Flutter作为开发语言,实现了demo演示问题,原生库、RN库同理可以解决问题。
    android版本:
    build.gradle

    compileSdkVersion 31
    minSdkVersion 21
    targetSdkVersion 31
    
    • 1
    • 2
    • 3

    futter版本:Flutter 2.10.5
    pubspec.yaml

    firebase_core: 1.10.0
    firebase_messaging: 10.0.0
    firebase_crashlytics: 2.2.0
    firebase_analytics: 9.1.0
    firebase_performance: 0.7.0+3
    dio_firebase_performance: ^0.3.0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解决方案

    修改firebase_analytics插件,
    修改的源码,分支firebase_analytics-v9.1.0-20220913。

    等到用户同意后再执行,flutter调用以下方法,就会初始化FirebaseAnalytics。

    // flutter
    FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true)
    
    • 1
    • 2

    堆栈信息

    callstack:android.app.ApplicationPackageManager.getInstallerPackageName:2044;
    com.google.android.gms.measurement.internal.e3.k:8;
    com.google.android.gms.measurement.internal.c4.i:2;
    com.google.android.gms.measurement.internal.y4.c:13;
    com.google.android.gms.measurement.internal.x4.run:1;
    java.util.concurrent.Executors$RunnableAdapter.call:458;
    java.util.concurrent.FutureTask.run:266;
    com.google.android.gms.measurement.internal.u4.run:6;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    官方反馈的堆栈信息,看得莫名其妙。只好根据之前的定位问题的方式,找到栈顶方法,进行debug调试。
    在这里插入图片描述
    在这里插入图片描述

    分析问题

    从堆栈信息和debug断点模式来看,应用启动后就会执行到这,是gms(谷歌移动服务)发生的问题。那现在就要找到什么地方调用起来。

    尝试方案一

    根据之前的猜测可能是引入了gms相关的provider,自动初始化了。找到debug包中的AndroidManifest文件,查看有关的gms配置,我给每一项都加入tools:node=“remove”,移除该项配置,结果并没有用。

    	<receiver
                android:name="com.google.android.gms.measurement.AppMeasurementReceiver"
                android:enabled="true"
                android:exported="false" >
            </receiver>
    
            <service
                android:name="com.google.android.gms.measurement.AppMeasurementService"
                android:enabled="true"
                android:exported="false" />
            <service
                android:name="com.google.android.gms.measurement.AppMeasurementJobService"
                android:enabled="true"
                android:exported="false"
                android:permission="android.permission.BIND_JOB_SERVICE" />
            <service
                android:name="com.google.android.gms.auth.api.signin.RevocationBoundService"
                android:permission="com.google.android.gms.auth.api.signin.permission.REVOCATION_NOTIFICATION"
                android:exported="true" />
            <activity
                android:theme="@ref/0x01030010"
                android:name="com.google.android.gms.common.api.GoogleApiActivity"
                android:exported="false" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    尝试方案二

    既然与gms,查看堆栈,找到对应的库,发现是play-services-measurement-impl中触发的,那就想办法移除这个库。
    在这里插入图片描述

    在app的gradle中,移除com.google.android.gms相关的库,我发现两个都有触发的可能性,所以都移除了。

    configurations {
                    all {
    //                  // 重点是这个
                        exclude group: "com.google.android.gms", module: "play-services-measurement-sdk"
                        exclude group: "com.google.android.gms", module: "play-services-measurement-impl"
                    }
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再次运行后,发现不会再出现由这两个库引起调用getInstallerPackageName方法了。
    但在继续debug调试的过程,其他的gms库依然存在违规获取应用列表问题。如下图
    在这里插入图片描述
    我也play-services-measurement-basement库给移除掉,但移除后发现,app跑不起来。
    继续debug调试的过程,又又又发现其他gms库也存在问题,在移除 play-services-measurement-sdk-api或play-services-measurement-api时,会白屏,并且提示错误,FirebaseAnalytics.getInstance初始化失败。实在无力吐槽了。

    // 出现错误
    Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/internal/measurement/zzee;
            at com.google.firebase.analytics.FirebaseAnalytics.getInstance(com.google.android.gms:play-services-measurement-api@@20.0.0:1)
    
    • 1
    • 2
    • 3

    从这个错误,发现一点问题,好像与FirebaseAnalytics.getInstance的初始化有关,又去搜了一下google。android.gms.internal.measurement这个包有啥用,firebase官方文档还有真有这个类的介绍。
    在这里插入图片描述

    包含配置 Firebase Analytics 核心服务

    顺着FirebaseAnalytics.getInstance去找问题,找到该方法的位置。
    在这里插入图片描述
    发现FirebaseAnalytics类是在com.google.android.gms:play-services-measurement-api库中引入,那也证实了FirebaseAnalytics与gms某些库有关联。

    解决问题

    找到FirebaseAnalytics.getInstance调用时机。
    在这里插入图片描述
    问题发生在FirebaseAnalytics初始化,FirebaseAnalytics.getInstance(context);
    经过排查,发现在Flutter的插件FlutterFirebaseAnalyticsPlugin类中,在FlutterFirebaseAnalyticsPlugin被Flutter加载后,就执行了FirebaseAnalytics初始化方法,然后导致gms服务被加载,然后违规获取应用列表的行为。

    只要修改firebase_analytics插件,等到用户同意后再执行。
    github下载源码 基于v9.1.0分支

    public class FlutterFirebaseAnalyticsPlugin
        implements FlutterFirebasePlugin, MethodCallHandler, FlutterPlugin {
      private FirebaseAnalytics analytics;
      private MethodChannel channel;
      private Context context;
    
      private void initInstance(BinaryMessenger messenger, Context context) {
      // 第1步:注释掉这个位置
    //    analytics = FirebaseAnalytics.getInstance(context);
        this.context = context;
        String channelName = "plugins.flutter.io/firebase_analytics";
        channel = new MethodChannel(messenger, channelName);
        channel.setMethodCallHandler(this);
        FlutterFirebasePluginRegistry.registerPlugin(channelName, this);
      }
    
      /**
       * 第2步
       * 20220913自己加入一个方法,初始化
       */
      private void initFirebaseAnalytics(){
        if(this.context != null && this.analytics == null){
          Log.i("zzb", "初始化initFirebaseAnalytics");
          analytics = FirebaseAnalytics.getInstance(this.context);
        }
      }
      
      @Override
      public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        Task<?> methodCallTask;
    
        switch (call.method) {
          // 第3步,加入初始化方法,给flutter调用
          case "Analytics#initFirebaseAnalytics":
            initFirebaseAnalytics();
            return;
        }
      }
      
      private Task<Void> handleSetAnalyticsCollectionEnabled(final Map<String, Object> arguments) {
        return Tasks.call(
            cachedThreadPool,
            () -> {
              // 第4步,我偷懒,在handleSetAnalyticsCollectionEnabled方法进行初始化
              initFirebaseAnalytics();
              final Boolean enabled =
                  (Boolean) Objects.requireNonNull(arguments.get(Constants.ENABLED));
              if(analytics != null){
                Log.i("zzb", "执行analytics handleSetAnalyticsCollectionEnabled");
                analytics.setAnalyticsCollectionEnabled(enabled);
              }
              return null;
            });
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    由于Flutter与原生进行通信使用firebase_analytics_platform_interface库,如果还要修改firebase_analytics_platform_interface库,就要维护两个库,firebase_analytics和firebase_analytics_platform_interface,不想修改这个库的内容。

    所以偷懒的方式,把初始化方法,放在了现有的方法FlutterFirebaseAnalyticsPlugin.java的handleSetAnalyticsCollectionEnabled()中。
    Flutter层需要调用一次FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true)来初始化analytics。

    最后

    Firebase实在太恶心了,在国内强烈不建议使用!!!firebase生态库相互唤起,出问题了很难定位。

  • 相关阅读:
    HTML大学班级活动网页设计 、大学校园HTML实例网页代码 、本实例适合于初学HTML的同学
    常见亲脂性细胞膜染料DiO, Dil, DiR, Did光谱图和实验操作流程
    吃透SpringBoo的这些t知识,你就已经超过90%的Java面试者了
    【数学建模】2018年数学建模国赛C题 基于RFMT 模型的百货商场会员画像描绘
    java对文件和文件夹的操作,比如读取文件里面东西,遍历文件夹下的文件等操作
    网络配置(IP、NETMASK、GATEWAY、DNS、DHCP) <持续更新中>
    进程状态
    庖丁解牛 指针的高端操作
    想跳槽却简历石沉大海?一起来围观月薪 20k 的软件测试工程师真实简历
    如何把图片文字转换成文字?图片转文字方法推荐
  • 原文地址:https://blog.csdn.net/ZZB_Bin/article/details/126833757