android各版本兼容问题汇总

在开发过程中,遇到过各种各样的代码兼容问题,有些问题真的是让人头大。

这里做一个记录整理,各位网友有更多的兼容问题,欢迎留言,我好补充下来,给更多的网友做一个汇总,谢谢!

该博客持续更新!

1. android Q(10.0)无法获取到剪贴板的内容

官方链接:https://developer.android.com/about/versions/10/privacy/changes?hl=zh-cn

国内大家都会用搜狗、QQ这类第三方输入法,所以默认输入法就不用想了。目前正处于焦点的应用,经测试,在android 10.0以上的手机,从第三方应用复制回来之后,也会走onResume方法,但是直接在onResume方法获取剪贴板内容,就会得到空。那么按照官方的说明,我们应该是要获取应用的焦点,遗憾的是,搜遍文档,也没有看到系统提供的获得焦点的监听,所以这里建议大家在onResume方法的最后,做一个延迟加载来获取剪贴板的内容,至于延迟的时间,取决于布局的复杂程度(毕竟要布局加载完成,才能理解为应用获得了焦点),我这里是将时间设置为1秒。

Handler().postDelayed({
                getClipboardContent() //在这里写了个方法获取剪贴板的内容
            },1000)

2.android 8.0 以上版本开启service闪退

官方链接:https://developer.android.com/about/versions/oreo/android-8.0-changes.html#back-all

崩溃日志如下:

android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground() at 
android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220) at 
android.os.Handler.dispatchMessage(Handler.java:109) at 
android.os.Looper.loop(Looper.java:166) at 
android.app.ActivityThread.main(ActivityThread.java:7555) at 
java.lang.reflect.Method.invoke(Native Method) at 
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:469) at 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:963)

解决办法:

//启动服务的时候判断一下版本
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            startForegroundService(Intent(this,StepService::class.java))
        }else {
            startService(Intent(this, StepService::class.java))
        }
class StepService : Service() {

    override fun onCreate() {
        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        //这里判断一下版本,8.0以后的,要创建一个通知
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            createNotificationChannel()
        }
        return super.onStartCommand(intent, flags, startId)
    }

    @RequiresApi(Build.VERSION_CODES.O)
    private fun createNotificationChannel(){
        var mNotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        var id = "这里填包名"
        var name = "xxx"
        var description = "xxxxxx"
        var importance = NotificationManager.IMPORTANCE_DEFAULT
        var mChannel = NotificationChannel(id,name,importance)
        mChannel.description = description
        mNotificationManager.createNotificationChannel(mChannel)

        var intent = Intent(this, WebActivity::class.java) //这里是点击这个通知去哪里
        intent.putExtra("url", Contans.walkMoney)
        intent.putExtra("id","")
        intent.putExtra("icon","")
        intent.putExtra("name","")
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
        var pi = PendingIntent.getActivity(this,0,intent,0)

        var notification = Notification.Builder(this).setContentTitle("xxx")
             .setContentText("xxxxxx").setSmallIcon(R.mipmap.ic_launcher).setChannelId(id)
                .setContentIntent(pi).setAutoCancel(true)
                .build()
        startForeground(1,notification)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

NOTICE: 经实际测试,并非所有8.0以上的手机都会闪退,即部分8.0以上的手机,不调用startForegroundService 也不会闪退; 同时做了上述修正代码之后,在一些8.0以上的手机,也并不会出现通知,猜测和国内厂商修改android源码有关

3.剪贴板ClipData闪退

崩溃日志:

java.lang.SecurityException: tp.defen.guard from uid 10935 not allowed to perform READ_CLIPBOARD 
at android.os.Parcel.createException(Parcel.java:2087) at 
android.os.Parcel.readException(Parcel.java:2055) at 
android.os.Parcel.readException(Parcel.java:2003) at 
android.content.IClipboard$Stub$Proxy.setPrimaryClip(IClipboard.java:293) at 
android.content.ClipboardManager.setPrimaryClip(ClipboardManager.java:106) at 
//这里因为隐私问题,屏蔽了对应的包名的崩溃日志
android.view.View.performClick(View.java:7275) at 
android.view.View.performClickInternal(View.java:7227) at 
android.view.View.access$3800(View.java:829) at 
android.view.View$PerformClick.run(View.java:27920) at 
android.os.Handler.handleCallback(Handler.java:883) at 
android.os.Handler.dispatchMessage(Handler.java:100) at 
android.os.Looper.loop(Looper.java:238) at 
android.app.ActivityThread.main(ActivityThread.j$

根据崩溃日志,我去查了一下 tp.defen.guard这个app,名称叫 “强力杀毒卫士”,这个app可以禁止应用使用剪贴板,所以,无奈,只能在代码中加入try catch解决问题

try {
                                val mClipData: ClipData = ClipData.newPlainText("Label", "")
                                cm.primaryClip = mClipData
                            }catch (e:Exception){}

4.java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference

崩溃日志

 Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
java.lang.RuntimeException: Unable to start activity ComponentInfo{cn.binfenli.quanyika/cn.binfenli.quanyika.SplashActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2884)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2945)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.app.ActivityThread.-wrap12(ActivityThread.java)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1655)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.os.Handler.dispatchMessage(Handler.java:102)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.os.Looper.loop(Looper.java:154)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at android.app.ActivityThread.main(ActivityThread.java:6457)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at java.lang.reflect.Method.invoke(Native Method)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1000)
Error
	
06-04 10:17:14.414
	
18538
	
AndroidRuntime
	
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:890) 

Found activity ActivityRecord{26729e8 u0 (这里是包名)/.(崩溃的activity名) t445 f} in proc activity list using null instead of expected ProcessRecord{bcb3d65 18538:(包名)/u0a955} 

这个崩溃日志真是让人头痛,没有任何有用的信息,最下面一行的崩溃信息,是打开APP的启动页,也就是一打开APP就崩溃了,而且没有指向任何一行代码。在更下面的日志里面,找到一行指向的代码,是空指针,指向的是自定义的BaseActivity的OnCreate方法的

super.onCreate(savedInstanceState)这行代码

我简直吐了,这行代码怎么可能会引发空指针呢。

这里特别说明一下,笔者遇到这个问题,来自于第三方平台的崩溃监测,崩溃的手机:魅族

型号:meizu 16x , android版本:7.1.1

由于公司没有这台手机,云真机也没有这台手机,所以先找了一些android版本7.1.1的手机测试,测试了小米、华为、oppo、vivo的android 7.1.1的手机,均正常。最后终于在腾讯的wetest找到一台型号叫meizu 15的android 7.1.1的手机,果然,打开就闪退,只能说:垃圾魅族!!!

最后没办法呀,只能从头找原因

1.先是写了个testactivity,不再继承BaseActivity,而是继承AppCompatActivity,界面还是使用当时闪退的启动页的xml,打开,闪退,说明并不是BaseActivity的问题

2. 重新写一个xml,里面就一个textview,显示hello world,testactivity用这个布局,打开,闪退,说明也不是启动页的布局的问题

3.去除AndroidManifest.xml里面application的android:name,不再使用自定义的Application,打开,正常!!!

找到了原因,就开始在Application里面找原因,最后终于找到

companion object{

private var instances = MyApplication()

}

居然是这行代码导致的错误,难道是不允许在这里赋值一个对象?于是改成这样

private var instances:MyApplication? = null

在Application的OnCreate方法里面赋值

override fun onCreate() {
        super.onCreate()
         instances=this
}

问题解决,该问题目前笔者所遭遇的,只出现在魅族手机,android 7.1.1的系统

5.java.lang.RuntimeException: Using WebView from more than one process at once with the same data directory is not supported.

错误日志

java.lang.RuntimeException: Using WebView from more than one process at once with the same 
data directory is not supported. https://crbug.com/558377 at 
org.chromium.android_webview.AwBrowserProcess.b(PG:11) at D5.m(PG:33) at C5.run(PG:2) at 
org.chromium.base.task.TaskRunnerImpl.g(PG:11) at Xs.run(Unknown Source:2) at 
android.os.Handler.handleCallback(Handler.java:883) at 
android.os.Handler.dispatchMessage(Handler.java:100) at 
android.os.Looper.loop(Looper.java:238) at 
android.app.ActivityThread.main(ActivityThread.java:7827) at 
java.lang.reflect.Method.invoke(Native Method) at 
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at
 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

这个错误发生在代码设置的targetSdkVersion >=28并且手机是9.0以上的机器,是官方android P(9.0)的行为变更,不允许多进程使用同一目录webview

解决办法:在app的application类OnCreate方法中加入代码

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val processName = getProcessName()
            if (!"应用包名".equals(processName)) {
                WebView.setDataDirectorySuffix(processName)
            }
        }

6.部分手机(android 10.0以上系统)无法拉起微信小程序

在测试的过程中,被反馈部分手机无法拉起微信小程序,网上找资料的时候,找到如下资料:

华为Android 10手机微信小程序无法调起的问题解决办法 - 程序员大本营

说的有两点问题:

1. 检查微信的悬浮窗权限是否开启

2. 检查微信是否有显示在其他应用上层的权限

经检查,拉不起微信小程序的手机,的确是没有开启相应的权限(不是每台手机都有上述两个权限,笔者的华为mate30是只有2的权限),开启权限之后,是能正常拉起小程序了。但这不能成为解决方案,因为我们不能引导用户去做这个操作,于是经过测试,在拉起小程序的地方,先拉起微信,就可以了。

try {
                if(api!!.isWXAppInstalled){ //这个api是微信注册的返回,对象是IWXAPI
                    api!!.openWXApp() //判断是否有安装微信,有的话先拉起微信
                }
                //然后再拉起小程序
                var obj = JSONObject(json)
                var req = WXLaunchMiniProgram.Req()
                req.userName = obj.optString("userName")
                req.path = obj.optString("path")
                req.miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE
                api!!.sendReq(req)
            }catch (e:Exception){}

7.微信小程序左上角的返回按键或者自定义按钮调用返回事件,无法返回至APP,并且导致APP主进程被杀死

在第6点,APP拉起小程序之后,在对接到某个第三方的小程序时,发现对方的小程序和其它小程序不一样。它自定义了头部导航,左上角不是回到首页的图标,而是返回按键,在点击该按键时,无反应,但神奇的发现APP的进程不见了。

解决方案:AndroidManifest.xml文件中,找到 WXEntryActivity,添加启动模式

android:launchMode="singleTask"

其它任何模式都不行,必须是singleTask,具体原因暂不清楚

8.android12的机器,内部版本更新时提示解析包出现异常

这个很坑爹哈,一开始以为是代码的问题,网上各种搜,发现代码写法基本都一致的,没啥问题,代码如下:

val file = File(filePath)
val intent = Intent(Intent.ACTION_VIEW)
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
if (Build.VERSION.SDK_INT >= 24) { //判读版本是否在7.0以上
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    intent.addCategory(Intent.CATEGORY_DEFAULT)
    val contentUri = FileProvider.getUriForFile(context,
            context.packageName + ".provider", file)
    intent.setDataAndType(contentUri, "application/vnd.android.package-archive")
} else {
    intent.setDataAndType(Uri.parse("file://$filePath"), "application/vnd.android.package-archive")
}
context.startActivity(intent)

权限和provider的配置都是有加的:

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

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

file_paths的配置也都是OK的,这个网上的各种配置还有些许不同,我这一股脑的全部都给复制了过来

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--为了适配所有路径可以设置 path = "." -->
    <external-path name="external_files" path="." />
    <external-path name="tt_external_root" path="." />
    <external-path name="tt_external_download" path="Download" />
    <external-files-path name="tt_external_files_download" path="Download" />
    <files-path name="tt_internal_file_download" path="Download" />
    <cache-path name="tt_internal_cache_download" path="Download" />
    <external-path
        name="app_update_external"
        path="/" />
    <external-cache-path
        name="app_update_cache"
        path="/" />
</paths>

到此,我就死活找不出原因来了,最后通过各方排查,发现了区别,是有一台华为手机,系统版本是鸿蒙3.0.0,但实际内部基于的安卓版本是API 31,也就是android 12,就是这台机器会出现这个问题,其它相同的鸿蒙3.0.0的系统,API版本不是31的都没问题。最后终于找出原因:

var DOWNLOAD_FOLDER_NAME = Environment.DIRECTORY_DOWNLOADS 
/** 就是这行代码导致的,配置的下载目录是用的手机默认的download目录,
 * 解析出来的真实路径是:/storage/emulated/0/Download,而
* android 12不允许读取非应用内部的目录了,最后代码改成下面这个:
*/

var DOWNLOAD_FOLDER_NAME = KBaseApplication.getInstances().externalCacheDir?.path 
/** 这里的KBaseApplication是我自定义的application,
* 各位看官如果是在activity里面是可以直接用externalCacheDir的,
* 或者你只要传递了context,也可以用context.externalCacheDir。
* 这个目录读取出来的真实路径是:/storage/emulated/0/Android/data/包名/cache,
* 它就可以在android 12正常读取了
*/

另外,我使用的是系统的 DownloadManager来进行下载的,如果你也是使用这个的话,那么还有一行代码要修改一下:

val request = DownloadManager.Request(
                Uri.parse(DOWN_APK_URL))

//这里要使用setDestinationInExternalFilesDir,
//如果是使用setDestinationInExternalPublicDir的话,
//会报错: java.lang.IllegalStateException: Not one of standard directories

        request.setDestinationInExternalFilesDir(this,DOWNLOAD_FOLDER_NAME,
            File.separator+DOWNLOAD_FILE_NAME)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值