Android 10 (API 29)适配

重大隐私权变更

 隐私权变更受影响的应用缓解策略
 分区存储
针对外部存储的过滤视图,可提供对特定于应用的文件和媒体集合的访问权限
访问和共享外部存储中的文件的应用使用特定于应用的目录和媒体集合目录
了解详情
 增强了用户对位置权限的控制力
仅限前台权限,可让用户更好地控制应用对设备位置信息的访问权限
在后台时请求访问用户位置信息的应用确保在没有后台位置信息更新的情况下优雅降级
使用 Android 10 中引入的权限在后台获取位置信息
了解详情
 系统执行后台 Activity
针对从后台启动 Activity 实施了限制
不需要用户互动就启动 Activity 的应用使用通知触发的 Activity
了解详情
 不可重置的硬件标识符
针对访问设备序列号和 IMEI 实施了限制
访问设备序列号或 IMEI 的应用使用用户可以重置的标识符
了解详情
 无线扫描权限
访问某些 WLAN、WLAN 感知和蓝牙扫描方法需要获得精确位置权限
使用 WLAN API 和蓝牙 API 的应用针对相关使用场景请求 ACCESS_FINE_LOCATION 权限
了解详情

 

1.存储权限

  1. Android Q文件存储机制修改成了沙盒模式,应用只能访问自己沙盒下的文件和公共媒体文件,不可直接访问外部存储(/sdcard)文件,否则抛异常
  2. 对于Android Q以下,还是使用老的文件存储方式
  3. Android Q不再需要申请文件读写权限(删除了READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE两项危险权限),所以,Q以上不需要再动态申请文件读写权限。
  4. 谷歌官方推荐应用在沙盒内存储文件的地址为Context.getExternalFilesDir()下的文件夹。比如要存储一张图片,则应放在Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)中---》对应路径/Android/data/包名/files/Pictures
  5. 访问系统媒体文件:比如照片,音乐,视频等,需要使用MediaStore来进行访问,并且需要达成两个条件:

    ①拥有READ_EXTERNAL_STORAGE权限

    ②对应访问文件位于以下明确定义的媒体集合中

    照片, 存储在MediaStore.Images

    音频, 存储在MediaStore.Audio

    视频, 存储在 MediaStore.Video

  6. 存储兼容 :
    如果应用targetSDK<=P,并且应用安装在从 Android P 升级到 Android Q 的设备上。app的存储权限不受影响;
    如果应用重新安装在Android Q设备上,不管targetSDK是否是Q,app的存储权限都会受影响,那么必须对应用进行存储权限改动的适配;
  7. 如果targetSDK是Q,但是不想启用分区存储,可以在配置文件中配置下
     <application
            android:requestLegacyExternalStorage="true"
            .....

    这是为了给开发者更多时间适应这个变化,但是不知道什么时候回强制启用分区存储,还需尽快适配

2.定位权限
      1.
Android Q 引入了新的位置权限 ACCESS_BACKGROUND_LOCATION,该权限仅会影响应用在后台运行时对位置信息的          访问权。如果应用targetSDK<=P,请求了ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION权限,Android          Q设备会自动帮你申请ACCESS_BACKGROUND_LOCATION权限。
      2.如果应用以 Android 10 或更高版本为目标平台,则您必须在应用的清单文件中声明 ACCESS_BACKGROUND_LOCATION 权限并             接收用户权限,才能在应用位于后台时接收定期位置信息更新。
         以下代码段展示了如何在应用中请求在后台访问位置信息:

    <manifest ... >
        <!--允许获得精确的GPS定位-->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        <!--允许获得粗略的基站网络定位-->
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <!-- 兼容10.0系统,允许App在后台获得位置信息 -->
        <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
    </manifest>
    

      3.以下代码段中显示了定位权限检查逻辑的示例:

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
            == PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
       boolean backgroundLocationPermissionApproved =
               ActivityCompat.checkSelfPermission(this,
                   permission.ACCESS_BACKGROUND_LOCATION)
                   == PackageManager.PERMISSION_GRANTED;

       if (backgroundLocationPermissionApproved) {
           // App can access location both in the foreground and in the background.
           // Start your service that doesn't have a foreground service type
           // defined.
       } else {
           // App can only access location in the foreground. Display a dialog
           // warning the user that your app must have all-the-time access to
           // location in order to function properly. Then, request background
           // location.
           ActivityCompat.requestPermissions(this, new String[] {
               Manifest.permission.ACCESS_BACKGROUND_LOCATION},
               your-permission-request-code);
       }
    } else {
       // App doesn't have access to the device's location at all. Make full request
       // for permission.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
            },
            your-permission-request-code);
    }
    

      4.如果您的应用通常需要在被置于后台后(如当用户按设备上的主屏幕按钮或关闭设备的显示屏时)访问设备的位置信息。             要在这种特定类型的用例中保留对设备位置信息的访问权,请启动您已在应用的清单中声明前台服务类型为 "location" 的           前台服务:

    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        ...
    </service>
    

        在启动该前台服务之前,请确保您的应用仍可访问设备的位置信息:

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this,
            permission.ACCESS_COARSE_LOCATION) ==
            PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
        // App has permission to access location in the foreground. Start your
        // foreground service that has a foreground service type of "location".
    } else {
       // Make a request for foreground-only location access.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION},
           your-permission-request-code);
    }
    

3.后台启动App的限制
    Android10中, 当App无前台显示的Activity时,其启动Activity会被系统拦截, 导致启动无效。
    对此官方给予的折中方案是使用全屏Intent(full-screen intent), 既创建通知栏通知时, 加入full-screen intent 设置, 示例代码如下(基于官方文档修改):

Intent fullScreenIntent = new Intent(this, CallActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder notificationBuilder =
        new NotificationCompat.Builder(this, CHANNEL_ID)
    .setSmallIcon(R.drawable.notification_icon)
    .setContentTitle("Incoming call")
    .setContentText("(919) 555-1234")
    //以下为关键的3行
    .setPriority(NotificationCompat.PRIORITY_HIGH)
    .setCategory(NotificationCompat.CATEGORY_CALL)
    .setFullScreenIntent(fullScreenPendingIntent, true);
    
NotificationManager notifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notifyManager.notify(notifyId, builder.build());

注意:在Target SDk为29及以上时,需要在AndroidManifest上增加USE_FULL_SCREEN_INTENT申明

//AndroidManifest中
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />

测试结果:当手机处于亮屏状态时, 会显示一个通知栏, 当手机处于锁屏或者灭屏状态时,会亮屏并直接进入到CallActivity中

4.设备唯一标识符

   从 Android Q 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 签名权限才能访问设备的不可重置标识符(包含 IMEI 和序列号),然而READ_PRIVILEGED_PHONE_STATE权限只提供给系统app,所以不能通过((TelephonyManager) getActivity() .getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId()获取了

当前获取设备唯一ID的方式为使用SSAID, 若获取为空的话则使用UUID.randomUUID().toString()获得一个随机ID并存储起来, 该ID保证唯一, 但App卸载重装之后就会改变,SSAID获取方式:

String id = android.provider.Settings.Secure.getString(context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

5.非 SDK 接口限制

非SDK接口限制就是某些SDK中的私用方法,如private方法,你通过Java反射等方法获取并调用了。那么这些调用将在target>=P或target>=Q的设备上被限制使用,当你使用了这些方法后,会报错:

android Q适配

android stuido 下载地址

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值