【Android】不同系统API版本_如何进行兼容性配置
三三要成为安卓糕手
一:需要在设置页面手动授予的权限
这类权限涉及到比较高的系统权限或者是用户隐私,应用内部不能直接获取,所以需要跳转系统设置页,让用户自己开启权限
//SYSTEM_ALERT_WINDOW:允许应用在其他应用的上层显示窗口。用户需要在设置中手动授予这个权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Intentintent=newIntent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);//REQUEST_INSTALL_PACKAGES:允许应用安装其他 APK 文件。用户需要在设置中手动授予这个权限。
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);//WRITE_SETTINGS:允许应用修改系统设置。用户需要在设置中手动授予这个权限。
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
Intentintent=newIntent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);//ACCESS_NOTIFICATION_POLICY:允许应用访问或修改通知策略。用户需要在设置中手动授予这个权限
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
Intent intent = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
startActivity(intent);//MANAGE_EXTERNAL_STORAGE:允许应用访问所有外部存储文件。用户需要在设置中手动授予这个权限。
//安卓13(api版本33)开始,安卓引入“分区存储模式”以限制应用对存储文件的访问,当前这个权限几乎相当于自由读写所有文件
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
二:引导用户开启App安装权限
1:声明权限
2:申请权限
public class SettingsPermissionActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_settings_permission);findViewById(R.id.btn_install).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {boolean b = canInstallPermission();if (b){Toast.makeText(SettingsPermissionActivity.this,"已拥有权限",Toast.LENGTH_SHORT).show();}else {//可能安卓版本低,需要处理申请权限流程;也有可能是8.0以下的版本默认有了这个权限Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);}}});}private boolean canInstallPermission(){boolean install = true;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {install = getPackageManager().canRequestPackageInstalls();}return install;}
}
3:getPackageManager.canRequestPackageInstalls
这个方法仅支持安卓8.0(API26)以上的版本使用;
作用:能够准确判断出应用是否拥有请求安装包的权限,返回值类型为boolean;
低版本安卓,没有这种专门用于检查应用能否请求安装包的权限机制,可以会造成后续的一些代码(install的值)逻辑错误
例如,即使应用实际上没有获取到在低版本系统上安装应用所需的相关权限(比如 android.permission.INSTALL_PACKAGES
,且在 Android 8.0 之前需要系统签名的应用才拥有该权限 ),由于没有执行 canRequestPackageInstalls()
方法,install 变量仍为 true,可能导致后续安装尝试失败。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {install = getPackageManager().canRequestPackageInstalls();}
- 如果应用已经被授予了请求安装包的权限, 该方法会返回
true
,那么最终install
的值就是true
。 - 如果应用没有被授予请求安装包的权限 ,该方法会返回
false
,最终install
的值就是false
。
4:修改最小版本号
修改为26,意味着这个应用程序最低支持运行在 Android 8.0(Oreo)系统版本上,
三:进阶_去设置界面开启权限
1:代码
public class SettingsPermissionActivity extends AppCompatActivity {private TextView textView;private ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),new ActivityResultCallback<ActivityResult>() {@Overridepublic void onActivityResult(ActivityResult o) {if (o.getResultCode() == RESULT_OK){if(canInstallPermission()){Toast.makeText(SettingsPermissionActivity.this,"授权成功获取到了App的安装权限",Toast.LENGTH_SHORT).show();textView.setText(canInstallPermission() ? "已获取app安装权限" : "还未获取app安装权限");}}else if (o.getResultCode() == RESULT_CANCELED){Toast.makeText(SettingsPermissionActivity.this,"授权失败",Toast.LENGTH_SHORT).show();}}});@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_settings_permission);findViewById(R.id.btn_install).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {boolean b = canInstallPermission();if (b){//如果是26以下安卓版本还需要去补充逻辑//例如,即使应用实际上没有获取到在低版本系统上安装应用所需的相关权限// (比如 android.permission.INSTALL_PACKAGES ,// 且在 Android 8.0 之前需要系统签名的应用才拥有该权限 ),// 由于没有执行 canRequestPackageInstalls() 方法,install 变量仍为 true,可能导致后续安装尝试失败。Toast.makeText(SettingsPermissionActivity.this,"已拥有权限",Toast.LENGTH_SHORT).show();}else {//可能安卓版本低,需要处理申请权限流程;Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);String uri = "package:" + getPackageName();intent.setData(Uri.parse(uri));activityResultLauncher.launch(intent);}}});textView = findViewById(R.id.tv_info);textView.setText(canInstallPermission() ? "已获取App的安装权限" : "还未获取app安装权限");}/*** 版本低于26返回install返回true* 版本高于26,当前应用没有获得 “请求安装其他应用” 的权限。返回false,就需要用户手动去设置界面获取权限* 版本高于26,当前应用已经获得 “请求安装其他应用” 的权限。返回true* @return*/private boolean canInstallPermission(){boolean install = true;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {install = getPackageManager().canRequestPackageInstalls();}return install;}
}
2:指定跳转包名_字符串拼接
(1)拼接包名
指定当前需要跳转的app设置页面的包名,build中可以查询到
namespace
:
假设你有一个大型 Android 项目,包含多个模块,如一个主应用模块app
,以及用于支付功能的payment
模块和用于社交分享的share
模块。你可以分别设置namespace
为com.example.myapp
、com.example.myapp.payment
、com.example.myapp.share
,方便构建系统管理各个模块的资源和代码。applicationId
:
如果你开发了一个名为 “My Cool App” 的应用,为了在 Android 系统和应用商店中唯一标识它,你可能设置applicationId
为com.mycompany.mycoolapp
。当你后续对应用进行更新迭代,无论是修复 bug 还是添加新功能,都需要保持这个applicationId
不变,以便用户能正常接收应用更新。
简而言之:前置更侧重于不同Adroid不同模块的命名和代码的组织,后者更侧重于标识app唯一;建议如果要更改包名,要么一起改,要么都不改
(2)跳转页面选择使用ActivityResultLauncher
回调函数中
RESULT_OK
不代表 “权限已授予” :
它仅表示 “用户从设置页面正常返回了当前应用”,可能用户开启了权限,也可能没开启(比如打开设置页面后直接返回)。因此必须通过canInstallPermission()
再次检查权限状态,才能确认是否授权成功。- 也就是ActivityResult中的mResultCode=-1对应RESULT_OK
RESULT_CANCELED
的含义:
通常表示 “设置页面被异常关闭”(比如用户未操作就强制退出),此时可视为用户未完成授权,提示 “授权失败”。- 也就是ActivityResult中的mResultCode=0对应RESULT_CANCELED
(3)封装canInstallPermission()
内部代码就是用来判断,当前是否有安装权限的,复用代码