Android简单适配9.0~12.0
适配6.0~8.0的可以看下这个:
适配Android6.0到8.0详细过程——小白教程
注意:10.0到12.0的都是些网上看到的资料,我就适配到10.0的文件存储,如有不对的,可以留言,我会查阅修改,谢谢0.0
Android 9.0适配:
限制明文传输:
当 SDK 版本大于 API 28 时,默认限制了 HTTP 请求,并出现相关日志
java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted
by network security policy
该问题有两种解决方案:
1、在 AndroidManifest.xml 中 Application 节点添加如下代码
<application android:usesCleartextTraffic="true">
2、在 res 目录新建 xml 目录,已建的跳过,在xml目录新建一个network_security_config.xml文件,然后在AndroidManifest.xml 中 Application 添加如下节点代码。
android:networkSecurityConfig="@xml/network_security_config"
network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config cleartextTrafficPermitted="true" />
</network-security-config>
启动Activity:
在9.0 中,不能直接非 Activity 环境中(比如Service,Application)启动 Activity,否则会崩溃报错,
这类问题一般会在点击推送消息跳转页面这类场景,解决方法就是 Intent 中添加标志FLAG_ACTIVITY_NEW_TASK,
Intent intent = new Intent(this, TestActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
适配刘海屏:
使用开源库NotchAdapter,github地址:NotchAdapter
当我们需要以全屏及沉浸的模式显示我们的页面时,就需要适配刘海屏。
1、添加依赖:
//适配刘海屏的adapterimplementation 'cn.jerechen:notchAdapter:1.0.3'
2、在需要适配刘海的Activity中:
//添加 @RequiresApi(api = Build.VERSION_CODES.P) 注解 表示在9.0以上起效btn_keep_out = findViewById(R.id.btn_keep_out);INotchScreen notchScreen = NotchManager.INSTANCE.getNotchScreen();if (notchScreen!=null){ //notchScreen不为空代表是刘海屏boolean isContainNotch = notchScreen.isContainNotch(this);Log.e("MainActivity", "portrait activity isContainNotch : "+isContainNotch);notchScreen.getNotchInfo(this, new INotchScreen.NotchInfoCallback() {@Overridepublic void getNotchRect(Rect rect) {Log.e("MainActivity", "Rect Bottom : "+rect.bottom);//将被刘海挡住的 btn_keep_out 向下移动一个 刘海高度 距离RelativeLayout.LayoutParams lp =(RelativeLayout.LayoutParams) btn_keep_out.getLayoutParams();//在原有的 topMargin 基础上再加上 刘海屏的高度lp.topMargin += rect.bottom;btn_keep_out.setLayoutParams(lp);}});}
效果如下:
正常无刘海屏:
9.0手机模拟有刘海屏:
Android 10.0适配:
1、Scoped Storage(分区存储)
在Android 10上即使你拥有了储存空间的读写权限,也无法保证可以正常的进行文件的读写操作。
适配
最简单粗暴的方法就是在AndroidManifest.xml中添加android:requestLegacyExternalStorage="true"来请求使用旧的存储模式。
<applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"android:extractNativeLibs="true"android:usesCleartextTraffic="true"android:requestLegacyExternalStorage="true">
2、权限变化
1)在后台运行时访问设备位置信息需要权限(不建议)
Android 10 引入了 ACCESS_BACKGROUND_LOCATION 权限(危险权限)。
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
该权限允许应用程序在后台访问位置。如果请求此权限,则还必须请求ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION权限。只请求此权限无效果。
官方推荐使用前台服务来实现,在前台服务中获取位置信息。
首先在清单中对应的service中添加 android:foregroundServiceType="location":
<serviceandroid:name="MyNavigationService"android:foregroundServiceType="location" ... >...
</service>
启动前台服务前检查是否具有前台的访问权限:
boolean permissionApproved = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;if (permissionApproved) {// 启动前台服务} else {// 请求前台访问位置权限}
如此一来就可以在Service中获取位置信息。
2)一些电话、蓝牙和WLAN的API需要精确位置权限
3、后台启动 Activity 的限制(不太需要管,问题不大)
简单解释就是应用处于后台时,无法启动Activity。 这一限制导致最明显的问题就是点击推送信息时,有些应用无法进行正常的跳转(具体的实现问题导致)。所以针对这类问题,可以采取PendingIntent的方式,发送通知时使用setContentIntent方法。
对于全屏 intent,注意设置最高优先级和添加USE_FULL_SCREEN_INTENT权限,这是一个普通权限。比如微信来语音或者视频通话时,弹出的接听页面就是使用这一功能。
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
4、深色主题
适配方法有两种:
1)手动适配(资源替换)(建议使用,可以基本达到预想效果。)
将Application和Activity的主题修改为集成自Theme.AppCompat.DayNight或者Theme.MaterialComponents.DayNight,就可以对于大部分的控件得到较好的深色模式支持。
<application...android:theme="@style/AppTheme"...>
<!-- Base application theme. --><!--<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">--><style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar"><!-- Customize your theme here. --><item name="colorPrimary">@color/colorPrimary</item><item name="colorPrimaryDark">@color/colorPrimaryDark</item><item name="colorAccent">@color/colorAccent</item></style>
- 颜色:新建
values-night
文件夹,里面是深色模式下的colors.xml
文件
例如:
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="colorPrimary">#303030</color><color name="colorPrimaryDark">#232323</color><color name="colorAccent">#008577</color>
</resources>
- 图片:新建
drawable-night-xxhdpi
图片文件夹
按照ui设计给的深色模式图放进这个文件夹,系统就会在识别到深色模式后加载这个文件夹的资源了。
关键工具类NightModeUtil:
public class NightModeUtil {/*** 当前系统是否是深色模式*/public static boolean isNightMode(Context context) {int uiMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return uiMode == Configuration.UI_MODE_NIGHT_YES;}/*** 获取是否跟随系统,默认true*/public static boolean getSystemMode() {return SPUtils.getBoolean(Constants.KEY_MODE_SYSTEM, true);}public static void setSystemMode(boolean nightMode) {SPUtils.putBoolean(Constants.KEY_MODE_SYSTEM, nightMode);}/*** 获取是否设置深色模式,默认false*/public static boolean getNightMode() {return SPUtils.getBoolean(Constants.KEY_MODE_NIGHT, false);}public static void setNightMode(boolean nightMode) {SPUtils.putBoolean(Constants.KEY_MODE_NIGHT, nightMode);}public static void initNightMode() {initNightMode(getSystemMode(), getNightMode());}/*** 初始化App深色模式** @param systemMode 是否是跟随系统* @param nightMode 是否是深色模式*/public static void initNightMode(boolean systemMode, boolean nightMode) {if (systemMode) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);} else {if (nightMode) {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);} else {AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);}}}/*** 重启App*/public static void restartApp(Activity activity) {final Intent intent = App.getInstance().getPackageManager().getLaunchIntentForPackage(App.getInstance().getPackageName());if (intent != null) {intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);activity.startActivity(intent);android.os.Process.killProcess(android.os.Process.myPid());}}
}
在Application里初始化
NightModeUtil.initNightMode();
切换状态后重启App
//两个参数分别是 是否跟随系统,是否选择深色模式
NightModeUtil.initNightMode(dayNightSwitch.isChecked, ctvCheckNight.isChecked);
NightModeUtil.restartApp(activity);
WebView的深色模式设置
引入implementation 'androidx.webkit:webkit:1.2.0'后可轻易的实现WebView的深色模式,不过有兼容问题,这和WebView的版本有关,WebView版本独立于Android版本。(亲测在系统6.0和7.1上无效。)
在有WebView的Activity的onCarete里加上如下代码:
WebSettings webSetting = webView.getSettings();
// 检查是否支持暗模式
if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {boolean isAppDarkMode;if (NightModeUtil.getSystemMode()) {// 是否是跟随系统isAppDarkMode = NightModeUtil.isNightMode(this);} else {isAppDarkMode = NightModeUtil.getNightMode();}if (isAppDarkMode) {WebSettingsCompat.setForceDark(webSetting, WebSettingsCompat.FORCE_DARK_ON);} else {WebSettingsCompat.setForceDark(webSetting, WebSettingsCompat.FORCE_DARK_OFF);}
}
这就是跟随系统深色模式做的配置了。
效果图如下:
2)自动适配(Force Dark)(不建议使用,效果差。)
应用必须选择启用 Force Dark,方法是在其主题背景中设置 android:forceDarkAllowed="true"。
监听深色主题是否开启
首先在清单文件中给对应的Activity配置 android:configChanges="uiMode":
<activityandroid:name=".MyActivity"android:configChanges="uiMode" />
这样在onConfigurationChanged方法中就可以获取:
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {super.onConfigurationChanged(newConfig);int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;switch (currentNightMode) {case Configuration.UI_MODE_NIGHT_NO:// 关闭break;case Configuration.UI_MODE_NIGHT_YES:// 开启break;default:break; }
}
判断深色主题是否开启
其实和上面onConfigurationChanged方法同理:
public static boolean isNightMode(Context context) {int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
}
5、标识符和数据
对不可重置的设备标识符实施了限制
从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能正常使用以上这些方法。
Android 11 适配:
1、分区存储
Android 10之前,外部存储区的内容主要以两种形式存在,一种是由应用的包名命名,归属于特定应用目录下的内容,另一种是存储在公共存储区域的内容。
在Android 10 中,Google首次引入了分区存储,将公共区域划分成了不同的集合,并且在媒体文件和其他文档之间建立了清楚的分割。经过划分之后应用不可以随意访问外部存储区中的文件,而只能访问媒体文件。如果想访问包含更多细节数据的其他文档,应用专门向用户申请有关文档的访问权限。
分区存储是需要以 Android 10 为目标平台的,系统默认强制执行。
如果在 AndroidManifest 的application中添加了 requestLegacyExternalStorage=true 标志,就可以不受此限制。
但是当 target API 更新为 30 后,系统会忽略该配置。
如果有数据需要迁移,可以在 AndroidManifest 中将 preserveLegacyExternalStorage 属性设为 true ,当用户升级到以 Android 11 为目标平台时,这个配置就会生效。具体而言,这个配置在用户重新安装该应用前都是有效的。
针对以 Android 11 为目标平台的应用 (targetSdkVersion = 30) ,WRITEEXTENRNALSTORAGE 和 WRITEMEDIASTORAGE 不再提供其他任何访问权限 。
某些应用的核心功能可能需要访问大量的文件,例如文件管理操作、备份和恢复操作等等,此时就需要申请 MANAGEEXTERNALSTORAGE 权限。我们可以通过使用 ACTIONMANAGEALLFILESACCESS_PERMISSION intent 操作将用户引导至一个系统设置页面,让用户为应用授予所有文件的管理权限。
2、应用包可见性
在 Android 11 之前,我们可以通过 PackageManager.getInstalledPackages(0) 获取其他所有应用的包名等信息。
Android 11 为了增加安全性,更好地保护用户的隐私,对应用包的可见性做出了一些改动。
当 targetSdkVersion 为 30 时,如果我们用getPackageInfo(“another.app”,0) 获取其他应用包信息时 ,会出现 NameNotFoundException 的异常。
我们可以在 AndroidMainfest 中添加 <queries style="margin: 0px; padding: 0px;">来适配特定的使用场景:(该配置相当于是添加应用白名单)</queries>
3、权限变化
在 Android 11 中,系统为用户的私人数据提供了更多可供选择的授权方式,应用也加大了后台对位置的访问权限限制。
对应摄像头、位置信息和麦克风这几个数据类型,用户可以授予一次性的临时访问权限。
只要是在Android 11 上,该限制都会生效,如下 :
仅使用期间,仅限这一次等。
这个一次性权限的生效周期指的是:
应用 Activity 可见期间
应用转为后台后的短时间内
前台服务存活期间
当用户撤销单次授权后,应用进程退出,再次打开之后需要对应用进行重新授权期间
4、位置权限
在Android10 之前,我们通过ACCESSCOARRSELOCATION 或 ACCESSFINELOCATION(精确位置) 配置即可申请前后台位置权限。
Android 11将位置权限分为前台和后台两种权限。前文说的主要是前台权限,授权方式没有变化。应用想要申请后台权限,除了需要在清单文件中额外添加 ACCESSBACKGROUNDLOCATION 权限外,还需要应用主动引导用户到指定页面授权。
5、新功能
增加应用退出原因功能
在Android 11之前,我们想要了解应用退出的原因以及状态,都比较费劲。现 Android 11 引入了 方法:ActivityManager.getHistoricalProcessExitReasons() ,
可以让我们清楚地了解到应用退出的原因。
6、可变刷新率
应用和游戏现在可以为其窗口设置首选帧率。大多数 Android 设备以 60Hz 的刷新率更新屏幕,但是某些设备支持多种刷新率,例如 90Hz 和 60Hz,并可在运行时切换。在这些设备上,系统会基于首选帧率来为应用选择最佳刷新率。
Android12适配:
targetSdkVersion 31的应用在Android 12上安装时可能会存在两种安装不上的情况。
adb: failed to install xxx.apk: Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES:
Scanning Failed.: No signature found in package of version 2 or newer forpackage com.tomes.sharefile]
解决:
targetSdkVersion 30的应用必须使用v2及以上签名
adb: failed to install xxx.apk: Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: Failed
parse during installPackageLI: /data/app/vmdl2054463318.tmp/base.apk (at Binary XML file
line #49): com.tomes.ShareOpenTestActivity: Targeting S+ (version 10000 and above) requiresthat an explicit value for android:exported be defined when intent filters are present]
我们知道,当我们的应用以Android 12为目标,使用的activity,service,broadcast receiver含有intent-filter,则必须显示声明android:exported属性,如果没有声明,则我们的应用不能安装在Android 12上
解决方法:
声明android:exported属性即可解决。
如我上面的错误,只需要对ShareOpenTestActivity增加android:exported属性申明就好
<activity android:name=".ShareOpenTestActivity" android:exported="true"><intent-filter><action android:name="android.intent.action.SEND"/><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="text/*" /></intent-filter></activity>
总结:
targetSdkVersion为31【以Android 12为目标】的应用务必要加入v2签名,务必要对使用的activity,service,broadcast receiver含有intent-filter,显示声明android:exported属性。
Android简单适配9.0~12.0相关推荐
- android 11.0 12.0添加系统字体并且设置为默认字体
1.概述 在11.0 12.0系统定制化开发中,在产品定制中,有产品需求对于系统字体风格不太满意,所以想要更换系统的默认字体,对于系统字体的修改也是常有的功能,而系统默认也支持增加字体,所以就来添加楷 ...
- android 11.0 12.0第三方输入法app设置系统默认输入法
1.概述 在11.0 12.0的产品开发中,有功能需要要求设置默认输入法,替换掉系统的输入法,所以这就需要了解设置 输入法的相关功能需求,然后根据输入法包名来设置默认输入法 2.第三方输入法app设置 ...
- android 11.0 12.0设置app为默认浏览器
1.概述 在11.0 12.0的产品定制化中,如果系统安装多个浏览器时,需要设置默认浏览器来完成需求,这就需要看系统设置中的相关源码 当出现多个浏览器时,该如何设置默认浏览器呢, 其实在Setting ...
- Android 11.0 12.0蓝牙遥控器确认键弹不出输入法的解决方法
1.概述 在android11.0 12.0设备定制化开发时,遥控器是使用红外遥控器,也有使用蓝牙遥控器的,所以出现的问题不一定相同,今天遇到个问题就是蓝牙遥控器在输入数据时弹不出输入法的问题 首选排 ...
- android 11.0 12.0自定义开机向导app
1.概述 在11.0 12.0的系统产品开发中,需要自定义开机向导app页面,而系统源码中只提供了Provision作为开机向导app 有些平台没有把它编译到源码中 作为开机向导,所以自定义开机向导, ...
- Android 11.0 12.0系统默认开启wifi
1.概述 在11.0 12.0的系统中产品开发中,系统的wifi功能是默认关闭的,由于项目需要要求默认打开wifi,开机后直接连wifi就可以了 所以需要找到系统默认的关闭wifi的地方 打开wifi ...
- android 11.0 12.0控制屏幕亮屏和灭屏操作
在11.0 12.0的产品开发中, 需要提供亮屏和灭屏的接口在8.0以后系统对于屏幕亮灭屏做了限制,直接调用亮屏和灭屏的方法就调不到了, 接下来就来看PowerManage.java类 这个是一个电源 ...
- Android 10.0 11.0 12.0 启动模拟器教程
<<返回总目录 Android 10.0 11.0 12.0 启动模拟器教程 一.android 12.0 模拟器 二.安装android 10.0 11.0 12.0 SDK平台 三.创 ...
- Android 11.0 12.0屏蔽Launcher3桌面app图标的长按功能
1.概述 在11.0 12.0的产品定制化开发中,系统默认的Launcher3在workspace 第二屏通常都会显示app列表 点击进入app 列表页,长按app的icon图标会弹出 应用信息 弹窗 ...
- Android 11.0 12.0设置默认息屏时间
1.概述 在11.0 12.0定制化开发中,在系统设置中,息屏时间默认为1分钟,对于这个息屏时间感觉太短了,所以系统默认息屏时间修改也是常见的修改功能,在系统Settings中屏幕超时会根据默认息屏时 ...
最新文章
- 程序员编程时戴耳机是在听什么?
- Nature:人体菌群研究的25个里程碑
- apache http server指的是什么
- 二叉树深度和平衡二叉树的判定
- html5块元素代码,html5 区块与内联div 与span html块级元素(示例代码)
- Simulink之三相半波可控整流电路
- Visual C++ 设置适合自己的解决方案目录结构
- spring之Bean的生命周期
- pandownload事件_pandownload被执法背后是中国盗版的末路
- 考软件测试初学者眼影,Summer 大讲堂第一期:如何制作出版级的高分辨率图表?...
- xp系统能不能安装mysql_XP系统如何安装SQL2005?XP系统安装SQL2005图文教程
- 大学计算机与应用软件,深圳大学
- 原生JS与其他JS 区别
- 离散数学(第二版) 第一章、第二章习题
- 四川大学计算机学院研究生推免细则,四川大学计算机学院2012届硕士研究生推荐免试实施细则...
- CAD创建组却没有组合在一起?
- 计算机上机考试自我检查800字,检讨书自我反省800字考试没考好
- ElasticSearch集群黄色原因以及解决方案
- SDKMAN!使用指南
- 男女之间没有真正的友谊