Android6.0到9.0的适配,targetSdkVersion从23升级到26

> Android6.0到9.0的适配

Android6.0到9.0的适配爬坑总结- https://blog.csdn.net/feelinghappy/article/details/84521067

Android 6.0、7.0、8.0、9.0适配- https://www.jianshu.com/p/a8fd3d1fa0a3

-- 在调起这个申请动态权限后,权限框刚开发就瞬间消失了;
原因是:AndroidManifest(清单文件)中没有配置该权限;
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
在清单文件中也增加该权限就不会出现 权限框闪一下退出的问题了;

Android App兼容8.0和9.0- https://blog.csdn.net/u014644594/article/details/86748035
  1.项目中如果使用Volley的话,在android 9.0会出现异常,提示ProtocolVersion的异常,之后,就在AndroidManifest的application节点下添加,
  <!--解决android9.0上使用ProtocolVersion抛异常的bug--> org.apache.http.HttpStatus
        <uses-library android:name="org.apache.http.legacy" android:required="false" />

  2. Permission Denial: startForeground requires android.permission.FOREGROUND_SERVICE。
解决办法是在AndroidManifest中添加
<!--android 9.0上使用前台服务,需要添加权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

  3.<!-- 8.0安装apk权限,需要允许安装未知应用 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

<uses-library android:name="org.apache.http.legacy" android:required="false"/>
    <!--android 9.0上使用前台服务,需要添加权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />

Android 9.0中sdcard 的权限和挂载问题- https://blog.csdn.net/shift_wwx/article/details/85633801

getCacheDir()方法用于获取/data/data/<application package>/cache目录
getFilesDir()方法用于获取/data/data/<application package>/files目录
 通过Context.getExternalFilesDir()方法可以获取到 SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
 通过Context.getExternalCacheDir()方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据

-- android9.0来电无法获取处理:
  限制访问电话号码, 在未首先获得 READ_CALL_LOG 权限的情况下,除了应用的用例需要的其他权限之外,运行于 Android 9 上的应用无法读取电话号码或手机状态。
  与来电和去电关联的电话号码可在手机状态广播(比如来电和去电的手机状态广播)中看到,并可通过 PhoneStateListener 类访问。 但是,如果没有 READ_CALL_LOG 权限,则 PHONE_STATE_CHANGED 广播和 PhoneStateListener 提供的电话号码字段为空。

  要从手机状态中读取电话号码,请根据您的用例更新应用以请求必要的权限:
  要通过 PHONE_STATE Intent 操作读取电话号码,同时需要 READ_CALL_LOG 权限和 READ_PHONE_STATE 权限。
  要从 onCallStateChanged() 中读取电话号码,只需要 READ_CALL_LOG 权限。 不需要 READ_PHONE_STATE 权限。
  只用在项目权限列表添加权限:
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
android.permission.READ_CONTACTS android.permission.WRITE_CONTACTS

> targetSdkVersion从23升级到26

Android targetSdkVersion 26 升级后 应用内部版本更新失败的问题- https://blog.csdn.net/zy987654zy/article/details/83306445
Target sdk 26 (Android 8.0)一些版本兼容问题- https://blog.csdn.net/xinlvmylife/article/details/82837218
target-api 升级到26遇到的问题 国产ROM动态权限的坑- https://blog.csdn.net/weixin_33909059/article/details/87478034
关于targetSDKVersion=26适配8.0以上的一些坑- https://blog.csdn.net/u011449334/article/details/79193043
android 8.0 (API=26) 升级适配遇到的两个问题- https://blog.csdn.net/zp1307700/article/details/82688851

1.透明窗口设置的问题
Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
“有全屏不透明的activity才可以设置方向”
修改:(1)全屏设置,(2)透明设置,(3)方向设置
试了一下跟全屏好像没有什么关系,主要是
android:windowIsTranslucent=true(透明)
android:screenOrientation(方向)
的冲突。

解决方法:
(1)去掉android:screenOrientation;(可以横屏了,不太好,需求都被程序员改了);
(2)android:windowIsTranslucent 改为false; 如果需要透明的设置加上android:windowDisablePreview =true;

2.通知栏不显示的问题
https://developer.android.google.cn/training/notify-user/build-notification

自定义通知:
建议使用NotificationCompat.Builder

 new NotificationCompat.Builder(context, ID);
加上自定义的ID, 
或者使用NotificationCompat.Builder.setChannelId(ID)

> Android App兼容7.0, 8.0和9.0
安卓开发中,如果用vivo手机调试程序,很可能会遇到运行的时候安装应用失败。
Android Studio真机调试,vivo手机安装失败,解析包时出现问题
在工程目录的  gradle.properties  中添加以下代码即可:android.injected.testOnly = false
Android debug 包不能安装
gradle.properties 文件中添加:android.injected.testOnly=false

升级3.0之后自动启用了instant run功能,生成的apk包是不完整的,设置中关闭即可,应该是这个导致的
http://blog.csdn.net/sxw1900/article/details/78489294

 1.设置你的AS,关闭Instant Run。File->Settings->BUild,Execution...->Instant Run , 关闭勾选Enable Instant Run...
 2.在你的gradle.properties文件添加一句:android.injected.testOnly = false
------------

-- targetSdkVersion 26 升级
 1.Android 7.0系统,无法进行版本升级,提示文件解析失败。
第一步: 在res文件夹下面 创建xml文件夹。创建一个文件。文件名称:files_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="." name="文件名称自定义"/>
        <files-path path ="." name = "文件名称自定义"/>
        <cache-path path ="." name = "文件名称自定义"/>

        <external-path name="external_storage_root" path="." />
    </paths>
</resources>

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
                  
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/files_paths" />
        </provider>
第三步:在安装app的地方调整方式
 File apkfile : 这个是你的apk文件地址对象。
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Uri apkUri = FileProvider.getUriForFile(mContext, BuildConfig.APPLICATION_ID + ".provider", apkfile);  // 这个地方 关键
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.setDataAndType(apkUri, "application/vnd.android.package-archive");
            install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
            mContext.startActivity(install);
        } else {
            Intent i = new Intent(Intent.ACTION_VIEW);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
                    "application/vnd.android.package-archive");
            mContext.startActivity(i);
        }
 2.Android 8.0系统,安装Apk权限,添加未知应用的权限:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
解决方法: 添加允许安装未知应用市场权限,这个权限不是动态权限,所以不用进行动态申请。
//兼容8.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                boolean hasInstallPermission = getPackageManager().canRequestPackageInstalls();
                if (!hasInstallPermission) {
                    Tip.toast(this, "请打开安装未知应用的许可!");
                    startInstallPermissionSettingActivity(this);
                    return;
                }
            }
/**
     * 跳转到设置-允许安装未知来源-页面
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity(Context context) {
        //注意这个是8.0新API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

3.Android8.0通知栏 ,使得APP能在Android8.0中显示通知,需要进行版本判断,然后给builder设置Channel; 通知已经适配好了
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW);
                getNotifyMgr(context).createNotificationChannel(channel);
                builder = new NotificationCompat.Builder(context, id);
            } else {
                builder = new NotificationCompat.Builder(context);
            }

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            String channelId = "chat";
            String channelName = "聊天消息";
            int importance = NotificationManager.IMPORTANCE_HIGH;
            createNotificationChannel(channelId, channelName, importance);

            channelId = "subscribe";
            channelName = "订阅消息";
            importance = NotificationManager.IMPORTANCE_DEFAULT;
            createNotificationChannel(channelId, channelName, importance);
        }
    }


    @TargetApi(Build.VERSION_CODES.O)
    private void createNotificationChannel(String channelId, String channelName, int importance) {
        NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
        NotificationManager notificationManager = (NotificationManager) getSystemService(
                NOTIFICATION_SERVICE);
        notificationManager.createNotificationChannel(channel);
    }
}

类似于微信的App,其中App通知主要可以分为两类,一类是我和别人的聊天消息,这类消息非常重要,因此重要等级我设为了IMPORTANCE_HIGH。另一类是公众号的订阅消息,这类消息不是那么重要,因此重要等级我设为了IMPORTANCE_DEFAULT。除此之外,重要等级还可以设置为IMPORTANCE_LOW、IMPORTANCE_MIN,分别对应了更低的通知重要程度。
setPriority() 方法共有5个等级: 
1. PRIORITY_MIN - 最低级别(-2); 
2. PRIORITY_LOW - 较低级别(-1); 
3. PRIORITY_DEFAULT - 默认级别(0); 
4. PRIORITY_HIGH - 较高级别(1); 
5. PRIORITY_MAX - 最高级别(2);

IMPORTANCE_DEFAULT = 3;  会在状态栏中显示,允许有声音提示,但不会弹窗,通知下拉栏会展示
IMPORTANCE_HIGH = 4;  会弹窗提示,允许有提示音
IMPORTANCE_LOW = 2;  会在状态栏中显示,但不会弹窗,通知下拉栏会展示
IMPORTANCE_MAX = 5;   会弹窗提示,允许有提示音,可以使用全屏
IMPORTANCE_MIN = 1;    不提示,在通知下拉栏会展示,但是是收起的
IMPORTANCE_NONE = 0;  不提示,不展示

NotificationChannel channel = new NotificationChannel(CommonParams.NOTIFICATION_GROUP_DOWNLOAD,                    "下载通知消息", NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);

Android通知栏微技巧,8.0系统中通知栏的适配- https://blog.csdn.net/guolin_blog/article/details/79854070
Android 8.0系统通知栏适配Demo- https://download.csdn.net/download/sinyu890807/10349044
Android 8.0 通知适配-https://blog.csdn.net/y331271939/article/details/83342519
Android O 通知栏- https://github.com/YBill/NotificationTest https://github.com/OptimusPrimeRen/Android-O-Adaptive.git

public static void showChannel1Notification(Context context) {
        int notificationId = 0x1234;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//            Notification.Builder builder = new Notification.Builder(context, "group_download"); // 与channelId对应
            NotificationCompat.Builder builder = new NotificationCompat.Builder(context,"group_download");
            NotificationChannel channel = new NotificationChannel("group_download", // Constants.CHANNEL_CHAT group_download
                    "下载通知消息", NotificationManager.IMPORTANCE_DEFAULT);

            NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            mNotificationManager.createNotificationChannel(channel);

            // icon title text必须包含, 不然影响桌面图标小红点的展示
            builder.setSmallIcon(android.R.drawable.stat_notify_chat)
                    .setContentTitle("xxx")
                    .setContentText("xxx")
                    .setNumber(3); // 久按桌面图标时允许的此条通知的数量
//            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            mNotificationManager.notify(notificationId, builder.build());
        }

    }

// 通知栏的通知渠道ID
    public static final String NOTIFICATION_GROUP_DOWNLOAD = "carlife_group_download";
    public static final String NOTIFICATION_GROUP_NAME = "下载通知";

mNotificationManager = (NotificationManager) mActivity
                        .getSystemService(Context.NOTIFICATION_SERVICE);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    mBuilder = new NotificationCompat.Builder(mActivity, CommonParams.NOTIFICATION_GROUP_DOWNLOAD);
                    NotificationChannel channel = new NotificationChannel(CommonParams.NOTIFICATION_GROUP_DOWNLOAD,
                            CommonParams.NOTIFICATION_GROUP_NAME, NotificationManager.IMPORTANCE_DEFAULT);
                    channel.setSound(null, null);  //  不需要提示声音
                    mNotificationManager.createNotificationChannel(channel);
                } else {
                    mBuilder = new NotificationCompat.Builder(mActivity);
                }

                mBuilder.setSmallIcon(R.drawable.ic_launcher)
                        .setContentTitle(mActivity.getString(R.string.tts_setting_navi_voicepackage) + voiceName)
                        .setProgress(100, progress, false).setContentIntent(resultPendingIntent)
                        .setOngoing(true);

-- 关于Android 8.0后notification通知声音无法关闭或开启的问题
一、更新channelId,设置为一个新的值,跟以往任何一个都不重复,然后再设置channel.setSound(null, null);就可以了。 
二、卸载app,如果代码之前没问题,卸载重新安装就好了, 
三、手动调用清空channelId的方法,(这个我没试过,但应该是可以的) 
四、卸载app后把importance参数设置为NotificationManager.IMPORTANCE_LOW或者更低。再安装运行就好了。 
五、mBuilder.setOnlyAlertOnce(true)设置为true,这样的话,每次只会提醒一次声音,不会重复提醒。 
六、如果你不想卸载app的话,有个最好的办法就是同时更换channelId和NotificationManager.IMPORTANCE_LOW就可以了。

4. Android9.0
  .项目中如果使用Volley的话,在android 9.0会出现异常,提示ProtocolVersion的异常,之后,就在AndroidManifest的application节点下添加,
  <!--解决android9.0上使用ProtocolVersion抛异常的bug--> org.apache.http.HttpStatus
        <uses-library android:name="org.apache.http.legacy" android:required="false" />

   . Permission Denial: startForeground requires android.permission.FOREGROUND_SERVICE。
解决办法是在AndroidManifest中添加
<!--android 9.0上使用前台服务,需要添加权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

   .<!-- 8.0安装apk权限,需要允许安装未知应用 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

<uses-library android:name="org.apache.http.legacy" android:required="false"/>
    <!--android 9.0上使用前台服务,需要添加权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />

> 然后调研了下,都需要验证下:
 1.Android 7.0 files_paths.xml与FileProvider,文件共享;(已经适配)
 2.Android 8.0系统,安装Apk权限,添加未知应用的权限:应用内升级
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />;
 3.Android8.0通知栏问题;(已经适配); 8.0 App Logo圆形图标;
 4.Android9.0 <!--android 9.0上使用前台服务,需要添加权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
    <!--解决android9.0上使用ProtocolVersion抛异常的bug, Volley --> org.apache.http.HttpStatus
    <uses-library android:name="org.apache.http.legacy" android:required="false" />

startForeground requires android.permission.FOREGROUND_SERVICE
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

 5.升级安卓P之后,隐式广播将会被全面禁止,在AndroidManifest中注册的Receiver将不能够生效, 并在应用中进行动态注册
  非全屏透明Activity禁用设置orientation
非全屏透明页面不允许设置方向,否则会抛Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation异常,解决方案:android:windowIsTranslucent设置为false。
  6.在 Android 9.0 版本中,谷歌加入了非 SDK 接口使用限制,无论是通过调用、反射还是JNI等方式,开发者都无法对非 SDK 接口进行访问,此接口的滥用将会带来严重的系统兼容性问题。 在开发过程中,开发者如果调用了非 SDK 接口,会导致应用出现crash,无法启动;或在运行过程中出现崩溃、闪退等现象;也可能导致应用功能不可用等严重兼容性问题,其影响范围波及所有调用此接口的应用。
  非SDK接口的类型,分为三类:
(1)Light grey list: targetSDK>=P时,警告;
(2)Dark grey list: targetSDK<P时,警告;>=p时,不允许调用;
(3)Black list:三方应用不允许调用。

 7.如果该应用适配了8.0,则应用只能使用TYPE_APPLICATION_OVERLAY窗口类型来创建悬浮窗。(其它窗口类型在8.0已经被废弃掉)
TYPE_PHONE 
TYPE_PRIORITY_PHONE 
TYPE_SYSTEM_ALERT 
TYPE_SYSTEM_OVERLAY 
TYPE_SYSTEM_ERROR 
TYPE_TOAST

---------------------
mApkFile=/storage/emulated/0/release.apk
com.baidu.carlife was not granted  this permission: android.permission.WRITE_SETTINGS.
android.provider.Settings.isCallingPackageAllowedToPerformAppOpsProtectedOperation

Android系统下载管理DownloadManager功能
下载APK后打开APK,在安装时的报错 android.os.FileUriExposedException:exposed beyond app through Intent.getData()- https://blog.csdn.net/biickvtkd/article/details/78803481
下载安装APK(兼容Android7.0)- https://www.jianshu.com/p/577816c3ce93
Android 下载并安装apk,兼容7.0和8.0- https://blog.csdn.net/qq_33601179/article/details/85198222
Android 8.0 解决不能自动安装APK问题(完美适配)- https://blog.csdn.net/zzz2017/article/details/81172229
关于 Android 7.0 适配中 FileProvider 部分的总结- https://blog.csdn.net/c_furong/article/details/80362102

    <!--Android8.0允许安装未知来源权限(更新版本安装APK)-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="camera_photos" />
        <!--<external-path path="." name="external_storage_root"/>-->
        <external-path name="external_files" path="."/>
    </paths>
</resources>

<!--安卓7.0文件权限-->
        <provider
                android:name="carlife.support.v4.content.FileProvider"
                android:authorities="com.baidu.carlife.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">

            <!-- 元数据 -->
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_provider" />
        </provider>

<!--Android8.0允许安装未知来源权限(更新版本安装APK)-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

/**
     * 安装最新的apk包
     */
    public void installNewApk2(Activity activity) {
        LogUtil.e("desaco", "mApkFile=" + (Environment.getExternalStorageDirectory().toString() + "/carlife-release.apk"));
        mApkFile = new File(Environment.getExternalStorageDirectory().toString() + "/carlife-release.apk");
        if (mApkFile == null) {
            return;
        }
        // 安装应用
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Uri contentUri = FileProvider.getUriForFile(activity, "com.baidu.carlife.fileprovider", mApkFile );
            intent.setDataAndType(contentUri,"application/vnd.android.package-archive");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        } else {
            intent.setDataAndType(Uri.fromFile(mApkFile), "application/vnd.android.package-archive");
        }
        activity.startActivity(intent);
    }


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <paths>
    <!-- Context.getFilesDir() + "/path/" -->
    <files-path
        name="my_files"
        path="mazaiting/"/>
    <!-- Context.getCacheDir() + "/path/" -->
    <cache-path
        name="my_cache"
        path="mazaiting/"/>
    <!-- Context.getExternalFilesDir(null) + "/path/" -->
    <external-files-path
        name="external-files-path"
        path="mazaiting/"/>
    <!-- Context.getExternalCacheDir() + "/path/" -->
    <external-cache-path 
         name="name" 
         path="mazaiting/" />
    <!-- Environment.getExternalStorageDirectory() + "/path/" -->
    <external-path
        name="my_external_path"
        path="mazaiting/"/>
    <!-- Environment.getExternalStorageDirectory() + "/path/" -->
    <external-path
        name="files_root"
        path="Android/data/<包名>/"/>
    <!-- path设置为'.'时代表整个存储卡 Environment.getExternalStorageDirectory() + "/path/"   -->
    <external-path
        name="external_storage_root"
        path="."/>
  </paths>
</resources>

适配Android7.0应用内更新App和Android8.0安装未知来源的App

Android App兼容8.0和9.0- https://blog.csdn.net/wxz1179503422/article/details/83031724
AndroidP新特性适配处理- https://www.jianshu.com/p/f125ccb72da0
安卓P兼容Demo- https://github.com/YangHaoyi/AndroidPDemo

Android8.0适配那点事(一)- https://www.cnblogs.com/lrcaoxiang/p/9266944.html
Android 8.0 适配- https://www.jianshu.com/p/d9f5b0801c6b

-- Notification
IMPORTANCE_MIN 开启通知,不会弹出,但没有提示音,状态栏中无显示
IMPORTANCE_LOW 开启通知,不会弹出,不发出提示音,状态栏中显示
IMPORTANCE_DEFAULT 开启通知,不会弹出,发出提示音,状态栏中显示
IMPORTANCE_HIGH 开启通知,会弹出,发出提示音,状态栏中显示

-- 在Android 8.0中系统不允许后台应用创建后台服务。因此,Android 8.0引入了一种全新的方法,即Context.startForegroundService(),以在前台启动新服务。在系统创建服务后,应用有五秒的时间来调用该服务的startForeground()方法以显示新服务的用户可见通知,如果应用在此时间限制内未调用startForeground(),则系统将停止服务并声明此应用为ANR
if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
    getActivity().startForegroundService(intent);
}
else {
    getActivity().startService(intent);
}

-- 广播限制,Android 7.0(API级别25)对广播施加了一些限制,而Android 8.0让这些限制更为严格。
 针对 Android 8.0的应用无法继续在其清单中为隐式广播注册广播接收器
 应用可以继续在它们的清单中注册显式广播
 应用可以在运行时使用Context.registerReceiver()为任意广播(不管是隐式还是显式)注册接收器
 需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用

 在许多情况下,之前注册隐式广播的应用使用JobScheduler作业可以获得类似的功能
 注意,还有很多隐式广播当前不受此限制所限。 应用可以继续在其清单中为这些广播注册接收器,不管应用针对哪个API级别。

  使用Android7.0,在AndroidManifest中注册隐式广播的支持已经被删除了。当app在Android O上运行时,所有的在manifest中注册的隐式广播将会停止工作。
  最常见的不受影响的是ACTION_BOOT_COMPLETED,ACTION_HEADSET_PLUG,ACTION_CONNECTION_STATE_CHANGED用于蓝牙状态更改.
  JobScheduler很好的与Android系统和Doze模式相适应,他允许基于你定义的条件执行任务。 JobScheduler只支持Android棉花糖以及以上的系统,如果你的app的minSdkVersion小于21,则有类似API的库提供向后兼容,正式推荐的是FirebaseJobDispatcher。
  摆脱Manifest文件中的所有隐式广播,使用JobScheduler,FirebaseJobDispatcher或替代方案替代您的任务,如果不支持你的广播,那么请在activity、fragment、service中注册你的广播。

 能动态注册,就不静态注册;
 如果一定要静态注册, 发送的时候指定包名,即发送显式广播;
 如果要接收系统广播,而对应的广播在Android8.0中无法被接收,那么只能暂时把App的targetSdkVersion改为25或以下,但这招已经不顶用了,工信部要求targetSDK必须26以上;
 发送广播的时候携带intent.addFlags(0x01000000); 即能让广播突破隐式广播限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值