Android版本适配笔记(持续更新中)
uses-sdk
minSdkVersion:
支持安装的最低Android版本
targetSdkVersion:
表示创建的Android项目使用哪个API版本
- 手机的版本>
targetSdkVersion
所声明的版本,系统便可通过启用兼容性行为,如果需要使用高于targetSdkVersion
的特性,需要进行android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
的判断 - 手机的版本<
targetSdkVersion
所声明的版本,无法使用targetSdkVersion 中特有的版本特性
compileSDKVersion:
其目的是为了 在编译的时候检查代码的错误的警告,提示开发者修改和优化。可以使用@TargetApi
版本更新
Android 6.0 适配
- 在运行时请求权限
略 - 取消支持 Apache HTTP 客户端
如果需要使用:
android {
useLibrary 'org.apache.http.legacy'
}
- 硬件标识符访问权
通过蓝牙和 WLAN 扫描访问附近外部设备的硬件标识符,您的应用必须拥有[ACCESS_FINE_LOCATION]
或[ACCESS_COARSE_LOCATION]
权限。 - 通知
改用[Notification.Builder]
类来构建通知
Android 7.0 适配
1.应用间共享文件限制
尝试传递 file:// URI 会触发 FileUriExposedException
使用 [FileProvider]
类
file_provider_paths:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="captured_media"
path="captured_media/" />
<external-path
name="data"
path="Android" />
<cache-path
name="cache"
path="appCache" />
<external-path
name="external"
path="" />
</paths>
public static Intent getOpenFileIntent(Context context, File file) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context, "xxx.xxx.provider", file);
intent.setDataAndType(contentUri, downloadResponse.getMimeType());
} else {
intent.setDataAndType(Uri.fromFile(file), downloadResponse.getMimeType());
}
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
return intent;
}
-
APK Signature Scheme v2
Android 7.0 引入一项新的应用签名方案 :APK Signature Scheme v2
-
SharedPreferences
Android 7.0以后 应修改成MODE_PRIVATE -
系统广播删除
关闭了三项系统广播:网络状态变更广播、拍照广播及录像广播。
只有在通过 动态注册 的方式才能收到网络变化的广播,在AndroidManifest.xml
中静态的注册的无法收到。
Android 8.0 适配
- 后台服务限制
Android8.0之后,系统不允许后台应用创建后台服务.因此引入了一个全新的方法Context.startForegroundService()
,以在前台启动新服务.在系统创建服务后,应用有五秒时间来调用该服务的startForegroud()
方法来把后台服务推向前台显示并在通知栏显示服务可见
- 在Android 8.0中所有的通知都需要提供通知渠道,否则,所有通知在8.0系统上都不能正常显示。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
inal NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
mManager.createNotificationChannel(channel);
}
3.悬浮窗
如果该应用的targetSdkVersion >= 26,则应用只能使用TYPE_APPLICATION_OVERLAY
窗口类型来创建悬浮窗
4.Wifi:
每个后台应用可以在 30 分钟内扫描一次。
5.透明窗口
不允许锁定屏幕旋转
Android 9.0 适配
- 禁止明文流量的网络请求
network_security_config.xml
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">weather.com.cn</domain>
</domain-config>
- Wifi
每个前台应用可以在 2 分钟内扫描四次,所有后台应用总共可以在 30 分钟内扫描一次。
3.不允许共享 WebView 数据目录
如果开发者需要在多进程中使用 WebView,则必须先调用 WebView.setDataDirectorySuffix() 方法为每个进程设置用于存储 WebView 数据的目录。若多进程 WebView 之间需要共享数据,开发者需自己通过 IPC 的方式实现。
此外,若开发者只想在一个进程中使用 WebView,并且希望严格执行这个规则,可以通过在其他进程中调用 WebView.disableWebView() 方法,这样其他进程创建 WebView 实例就会抛出异常。
Android 10.0 适配
- 权限变化
- 权限单次允许
-
ACCESS_BACKGROUND_LOCATION 权限:
image.png
-
后台启动 Activity 的限制
应用处于后台时,无法启动Activity -
深色主题
-
随机分配 MAC 地址
-
获取imei需要 READ_PRIVILEGED_PHONE_STATE 权限
-
Scoped Storage(分区存储)
以前我们习惯使用Environment.getExternalStorageDirectory()方法,那么现在可以使用getExternalFilesDir()方法(包括下载的安装包这类的文件)。如果是缓存类型文件,可以放到getExternalCacheDir()路径下。
将图片保存到公共目录下:
public static Uri createImageUri(Context context) {
ContentValues values = new ContentValues();
// 需要指定文件信息时,非必须
values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
values.put(MediaStore.Images.Media.DISPLAY_NAME, "Image.png");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
values.put(MediaStore.Images.Media.TITLE, "Image.png");
values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/test");
return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}