Android api 22升级到api28 遇到的问题汇总

背景

         应国家电信终端产业协会要求,自2019年5月1日起,华为应用市场新上架应用应基于Android8.0(API Level 26)及以上版本开发。自2019年8月1日起,现有应用的更新应基于 Android8.0(API Level 26)及以上版本进行开发,安卓绿色联盟提醒广大应用开发者请提前做好准备,及时适配。
          这只是华为应用市场的一个提示,真实情况也是在今年5月份过后提交到各大应用市场发版的应用都会受到这样一份提醒,同时对于5月份之后的新APP上线发版都会被拒绝上线。

适配前的准备

           在计划适配到最高哪个版本之前需要确认和注意的有:

  1. 必须要将TargetSdkVersion提到26或以上版本
  2. 确认项目的影响范围(特别是古老的项目--别问我为啥要这么说)做好周期的评估
  3. 对于Android studio 开发工具来说升到最新版本有助于提升开发效率
  4. gradle 下载可以去官网(http://services.gradle.org/distributions/) 解压到本地  省时省力 方法很简单就不多言
  5. 第三方依赖需要提前做好调研,是否有最新的包同步更新,特别是一些小的三方功能组件,很可能作者已经
    停更了,这种情况就需要重写相应的功能,比较麻烦。因此在用三方小的组件库的时候一定要调研好。
  6. 更新一些大厂的基础库的时候,如推送、分享、地图、OCR、支付等等功能的时候要特别注意,非万不得已
    不要影响线上流程和功能。
  7. 如果是在api 22 基础上升到26或者更高版本,需要做好权限的控制,最直接的方式就是把清单文件中对应的危险权
    限梳理出来,根据功能进行权限申请(具体的权限工具类可以参考:https://github.com/pimian/androidPermission.git
  8. 对于api版本跨度较大的升级处理,最好是去官方网站上去看看每个api版本对应的升级特性都有哪些。

 开始适配

  1. 环境配置:

    SDK依赖直接升到28

    gradle 5.1.1

    build gradle 3.4.1

  2. 修改完之后直接编译查看编译器报错

    build.gradle  一般依赖报错解决方案如下

    testCompile ---》testImplementation

    compile ---》implementation

    androidTestCompile ---》androidTestImplementation
    如果有跨模块引用 compile ---》api

遇到报错问题:

  1. references to other resources are not supported by build-time PNG generation. 
     

    问题原因:

    添加多密度矢量图形的好处是使用矢量图代替位图可以减小 APK 的尺寸,因为可以针对不同屏幕密度调整同一文件的大小,而不会降低图像质量。对于不支持矢量图的较早版本 Android 系统,Vector Asset Studio 可在构建时针对每种屏幕密度将矢量图转换为不同大小的位图。

    解决方案:

    build.gradle 文件添加一条声明:

    android { defaultConfig { vectorDrawables.useSupportLibrary = true } }
     

  2. java.io.IOException: Cleartext HTTP traffic to xxx.xxx.xxx.xxx not permitted
     

    问题原因:

    Android 9.0是默认禁止所有http请求的,需要在代码中设置如以下代码才可以正常进行网络请求

    解决方案:

    方案 ① 在项目manifest中application节点中添加 android:usesCleartextTraffic=“true”

    方案 ② 在项目manifest中application节点中添加

    android:networkSecurityConfig="@xml/network_security_config"

    XML 文件中添加新文件 network_security_config.xml

    <network-security-config>

    <base-config cleartextTrafficPermitted="true" />

    </network-security-config>

  3. java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/ProtocolVersion;

    问题原因:

    这是GooglePlay Services方面的一个bug

    Android 6.0 中,取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情

    况下该内容库已从 bootclasspath 中移除且不可用于应用。

    解决方案:

    在项目manifest中application节点中添加子节点

    <uses-library android:name="org.apache.http.legacy" android:required="false" />

  4. 全屏展示引导层的时候刘海屏和非刘海屏的适配
     

    问题原因:

    在全屏引导的时候需要有一个半透明的遮罩层,在普通屏和刘海屏上展示的样式有错乱的表现,问题在于刘海屏和普通屏上 状态栏的高低处理方式有差异

    解决方案:

    在具体的调用页面上校验屏幕得硬件是否是刘海屏

    刘海屏判断(https://blog.csdn.net/pimian13611397598/article/details/97800780

    在不同的屏幕上使用的全屏代码区别:
     

     if (ScreenUtil.hasNotchInScreen(this)) {
          //刘海屏
        getWindow().setLayout(LinearLayout.LayoutParams.FILL_PARENT,  
          LinearLayout.LayoutParams.FILL_PARENT);
    } else {
        //普通屏
        getWindow().setLayout(LinearLayout.LayoutParams.MATCH_PARENT, 
           LinearLayout.LayoutParams.WRAP_CONTENT);
    }
  5. 全屏页面在Android 8.0上 IllegalStateException: Only fullscreen opaque activities can request orientation

    问题原因:

    从报错信息来看是 只有全屏不透明的活动界面才能设置oritation

    从代码层面来看:
    manifest:

    <activity
        android:name=".house.activity.DialogActivity"
        android:screenOrientation="behind"
        android:theme="@style/DialogTheme" />   

    style
     

    <style name="DialogTheme" parent="android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:background">@android:color/transparent</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:activityOpenEnterAnimation">@anim/fade_in</item>
        <item name="android:windowEnterAnimation">@anim/fade_in</item>
        <!--半透明-->
        <item name="android:windowNoTitle">true</item>
    </style>    

    解决方案:
          

    在 main activity上设置
     

    android:screenOrientation="portrait"

    在main activity  style文件中

    <item name="android:windowIsTranslucent">false</item>
  6. 百度小区街景点击方向引导按钮 闪退问题 java.lang.NullPointerException: Attempt to invoke interface method 'void com.baidu.lbsapi.panoramaview.PanoramaViewListener.onMoveStart()' on a null object reference
     

    问题原因:

    项目里面用到了百度的街景地图 更新到最新的版本之后就出现闪退,按报错来看是没有PanoramaViewListener 监听对象,结合百度地图街景api发现并没有必须设置当前监听的相关介绍,

    本着尝试的态度手动设置了一下PanoramaViewListener 问题修复
     

    解决方案:
     

     HzfApplication app = (HzfApplication) this.getApplication();
    if (app.mBMapManager == null) {
        app.mBMapManager = new BMapManager(app);
    
        app.mBMapManager.init(new HzfApplication.MyGeneralListener());
    }
    mPanoView = (PanoramaView) findViewById(R.id.panorama);
    if (lon == null) {
        lon = "0";
    }
    if (lat == null) {
        lat = "0";
    }
    mPanoView.setPanorama(Double.parseDouble(lon), Double.parseDouble(lat));
    mPanoView.setPanoramaImageLevel(PanoramaView.ImageDefinition.ImageDefinitionLow);
    mPanoView.setPanoramaViewListener(new PanoramaViewListener() {
        @Override
        public void onDescriptionLoadEnd(String s) {
            //Log.e("==","onDescriptionLoadEnd");
        }
    
        @Override
        public void onLoadPanoramaBegin() {
            //Log.e("==","onLoadPanoramaBegin");
        }
    
        @Override
        public void onLoadPanoramaEnd(String s) {
            //Log.e("==","onLoadPanoramaEnd");
        }
    
        @Override
        public void onLoadPanoramaError(String s) {
            //Log.e("==","onLoadPanoramaError");
        }
    
        @Override
        public void onMessage(String s, int i) {
            //Log.e("==","onMessage");
        }
    
        @Override
        public void onCustomMarkerClick(String s) {
            //Log.e("==","onCustomMarkerClick");
        }
    
        @Override
        public void onMoveStart() {
            //Log.e("==","onMoveStart");
        }
    
        @Override
        public void onMoveEnd() {
            //Log.e("==","onMoveEnd");
        }
    });     
  7. Android 7.0 开始FileProvider的使用Causedby:adroid.os.FileUriExposedException:

    问题原因及解决方案 : https://www.jianshu.com/p/577816c3ce93

  8. Android 8.0 开始延续了这么多年的apk静默安装也扛不住Google的大手了

    问题原因:

    在测试 8.0手机上版本升级功能是发现下载完apk文件之后无法跳转安装页面,通过报错信息发现是缺少android.permission.REQUEST_INSTALL_PACKAGES,Google从8.0 把未知应用的安装权限的管理放到了每个app上,每个app都有允许安装未知应用的设置开关。

    解决方案:

    在清单文件中声明

     <uses-permissionandroid:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

    下载完点击安装判断是否有权限

    if (Build.VERSION.SDK_INT >= 26) { 
        //来判断应用是否有权限安装apk
        boolean installAllowed= getPackageManager().canRequestPackageInstalls(); 
        //有权限
        if (installAllowed) { 
          //安装apk
          install(apkPath);
        } else { 
          //无权限 申请权限
          ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_APK_REQUESTCODE); 
        } 
      } else { 
        install(apkPath); 
    }

    具体的权限回调处理就不多说了

    多说一句安装适配

    if (Build.VERSION.SDK_INT >= 24) { //Android 7.0版本
        // 参数2 清单文件中provider节点里面的authorities ; 参数3  共享的文件,即apk包的file类
        //对目标应用临时授权该Uri所代表的文件
        installApkIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        installApkIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { //Android6.0 版本
        installApkIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        installApkIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
        installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    } else { //Android 5.0 以下版本
        installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        installApkIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
    }
    mcontext.startActivity(installApkIntent);
  9. Unable to resolve dependency for ':app@betaUnitTest/compileClasspath': Could not resolve project :XXXX

    遇到这个错误查看一下错误日志的报错内容 
    从Android studio 3.0 之后 lib依赖model build.gradle 里面 buildConfig  节点中的配置项必须和
    主工程app下build.gradle 中配置的一样  如:

    buildTypes {
            debug {
                    ....//我自己项目中的配置
            }
            beta {
                    ....//我自己项目中的配置
            }
            release {
                    ....//我自己项目中的配置
            }
        }

     那么引用的model中的配置也必须保持一致

  10. 升级gradle 之后打包的差异化
    多环境打包的时候 
    我们之前是这么写的

    android.applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    //这里修改apk文件名
                    def fileName = "app-release.apk"
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        }

    在新的gradle上面会报错   outputFile 找不到
    修改如下

    android.applicationVariants.all { variant ->
            variant.outputs.all {
                //这里修改apk文件名
                outputFileName = "app-release.apk"
            }
        }
    

猜你喜欢

转载自blog.csdn.net/pimian13611397598/article/details/97813668