问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Android 应用安装权限请求代码详解

创作时间:
作者:
@小白创作中心

Android 应用安装权限请求代码详解

引用
CSDN
1.
https://blog.csdn.net/i042416/article/details/146206760

在很多开发者需要为用户提供应用安装功能的场景里,这段 Android 代码发挥了关键作用。

它的目的在于检查当前设备是否具备安装来自未知来源的应用权限,如果尚未获得这项权限,就会引导用户去申请或启用该权限,以确保后续安装过程能够顺利完成。

在此先把完整代码贴出来,并对其中所有英文双引号进行替换:

private void checkAndStartInstallation() {
    boolean canRequestPackageInstalls;
    int i = Build.VERSION.SDK_INT;
    String $2 = "26";
    if (i >= 26) {
        canRequestPackageInstalls = getPackageManager().canRequestPackageInstalls();
        if (!canRequestPackageInstalls) {
            this.isWaitingForPermission = DEBUG;
            this.prefs.edit().putBoolean("A", DEBUG).apply();
            startActivityForResult(new Intent("B", (Uri) null), 5560);
            return;
        }
    }
    this.isWaitingForPermission = false;
    this.prefs.edit().putBoolean("A", false).apply();
    proceedWithInstallation();
}

有些时候,为了更好地说明问题,可以想象一个真实世界场景。假设用户小明在使用一款第三方应用商店,想要下载并安装一款并未上架到官方 Google Play 的游戏 APK。开发者在编写安装逻辑时,就可能写出上述检查权限的代码来确保用户可以顺利完成安装。如果用户所在的系统版本较高(例如 Android 8.0 及以上),系统对于未知来源的安装有更加严格的权限控制,需要用户显式地给予授权。这段代码正是用来在安装之前检查授权状态,并在需要时提示用户前往设置页面或通过弹窗来授予安装权限。

以下内容会对这段代码逐行进行剖析,并结合真实案例做说明:

private void checkAndStartInstallation() {

这行声明了一个名为 checkAndStartInstallation 的方法,作用是检查并启动安装流程。方法是私有可见性,说明它只能在当前类的内部被调用。假设在一个真实场景中,当用户点击了“安装”按钮时,就会调用这个方法来执行安装的前置检查。如果没有通过权限检查,则会先跳转去申请权限。

boolean canRequestPackageInstalls;

这一行声明了一个名为 canRequestPackageInstalls 的布尔变量,用来存储当前应用是否能够请求安装未知来源应用的权限。它还没有被赋值,需要在后续逻辑中根据系统返回值进行判断。

int i = Build.VERSION.SDK_INT;

这一行获取了当前设备的 SDK 版本号,并存储在 int 类型的变量 i 中。Build.VERSION.SDK_INT 表示当前系统的版本级别。例如, Android 8.0 的版本级别是 26, Android 9.0 是 28, Android 10 是 29 等等。假设小明的手机是 Android 9.0,那么这行代码执行完之后,i 的值就会是 28。

String $2 = "26";

这里定义了一个字符串类型的变量 $2,其值是 "26"。它看起来像是一个与版本号相关的常量值。因为 Android 8.0 的 API 级别正好是 26,所以可以推测这行代码是为了在后续逻辑中对比是否大于或等于 26。只是它的命名比较特殊,可能在示例或混淆环境中才会出现类似 $2 这样的名字。

if (i >= 26) {

这个条件判断是关键所在: 如果当前系统版本号 i 大于或等于 26,就说明手机运行的是 Android 8.0 或更高版本。在真实场景中,从 Android 8.0 开始,用户需要为每一个可能安装未知来源应用的 App 单独授予权限,而不再是以前那种在系统设置里统一开启“未知来源”的做法。所以如果 i >= 26,就必须检查这个单独的权限,否则就无法顺利安装。

canRequestPackageInstalls = getPackageManager().canRequestPackageInstalls();

这行代码调用 getPackageManager().canRequestPackageInstalls() 方法,来判断当前应用是否已经拥有请求安装未知来源应用的权限。结果会存储到 canRequestPackageInstalls 这个布尔变量里。如果这个值为 true,就代表已经拥有权限;如果为 false,就代表尚未获得该权限,需要额外申请。

以真实世界案例为例,假设小明的手机是 Android 10,开发者的应用想要安装一个外部来源的 APK。如果 canRequestPackageInstalls 的返回值是 false,就意味着小明的应用还没被授权允许安装未知来源的 APK,需要调用某些方法或跳转到设置页面来让小明授予权限。

if (!canRequestPackageInstalls) {

这行判断了如果没有请求安装包权限 (!canRequestPackageInstalls),就意味着需要进一步操作。很多时候,用户在第一次尝试安装时,往往会被系统弹窗或跳转页面告知需要启用权限。这里就是用来处理这种情况的逻辑分支。

this.isWaitingForPermission = DEBUG;

这行将当前对象的 isWaitingForPermission 变量赋值为 DEBUG。我们可以推测 DEBUG 这个布尔值在项目中可能等同于 true,表示正在等待用户授权。通过将 isWaitingForPermission 设置为 true,可以在后续某些回调或流程中知道自己正处于请求权限的状态,方便管理用户的操作流程。

从实际场景来理解,如果用户刚刚发起安装流程而没有权限,系统就需要弹出授权提示或者跳转设置。在跳转前,就可以设置一个标志位 isWaitingForPermission = true,以便在用户回到应用时能恢复之前的安装流程。

this.prefs.edit().putBoolean("A", DEBUG).apply();

这一行将某个名为 "A" 的布尔值存储到应用的 SharedPreferences 中,并调用 apply() 异步提交。这表示在持久化层面也记录了“当前正在等待权限”或其他相关状态,以防进程被杀死或应用被重启时,可以通过读取 SharedPreferences 来还原之前的状态。对于实际项目而言,这种做法能够在用户退出后再次进入应用时,让开发者知道自己是否正处于等待权限授权的阶段。

startActivityForResult(new Intent("B", (Uri) null), 5560);

这行代码启动了一个新的 Activity,并期望在返回时能够通过 onActivityResult 来得到结果。new Intent("B", (Uri) null) 里 "B" 代表的可能是一个特定的动作或者某个自定义的 Intent Action,用于跳转到系统的权限设置页面或者引导用户开启未知来源安装权限。5560 则是请求码,用于区分不同的 startActivityForResult 请求。

在真实世界里,常见的做法是跳转到 Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES 之类的页面,让用户手动勾选允许安装未知来源应用。不同机型或者定制系统可能会有不同的跳转方式。这里的 "B" 可能是一个自定义字符串,用于兼容厂商定制界面。

十一 return;

这行代码意味着,如果设备版本大于等于 26 并且还没有安装未知来源应用权限,就会直接返回,不执行后续的安装流程。这样做可以确保只有在用户成功授予权限后,才会继续执行安装操作。假设小明这时就会看到系统或应用弹出的对话框,引导他到设置界面。小明若选择同意授权,再回到应用时,才会继续走后面的流程。

十二 }

这行是 if (i >= 26) 语句块的结束大括号,表示上述检查和跳转逻辑只会在 Android 8.0 及以上的系统上执行。如果当前系统版本低于 26,就不会执行其中的跳转权限申请逻辑。低于 Android 8.0 的系统只有一个统一的未知来源开关,只要那个开关开启,应用就可以直接进行安装,不需要再做 per-app 的权限检查。

十三 this.isWaitingForPermission = false;

当代码执行到这里,说明有两种可能。一种是系统版本低于 26,不需要执行上面那段权限检查;另一种是系统版本大于等于 26 但已经拥有权限或者用户刚才已经通过某种方式授权完成。此时就将 isWaitingForPermission 设置为 false,表示我们不再处于等待用户授权的状态。

在真实应用场景中,如果某些业务逻辑需要知道自己是否还在等待权限,那么这里就是一个明确的信号告诉系统:“我们已经不需要等待授权了,可以进入下一步安装流程”。

十四 this.prefs.edit().putBoolean("A", false).apply();

这一行与前面的存储操作类似,只不过把 "A" 对应的值改为了 false,表示不需要再等待权限。这样即使应用被杀死或者设备重启,也能通过 SharedPreferences 读取到最新状态,知道当前不处于等待权限的阶段。真实案例中,这样的做法可以避免用户在授权完成后,应用却依然误以为自己还在等待授权,从而导致流程卡住。

十五 proceedWithInstallation();

这行调用了 proceedWithInstallation() 方法,真正开始执行后续的安装流程。比如,弹出安装对话框、解析 APK 文件、调用系统安装界面等。对于用户小明而言,当他看到这个阶段,通常就意味着可以看到正式的“是否安装此应用”提示对话框了。对于开发者而言,这里才是最终安装的关键一步。只有在确保了权限条件满足后,才能顺利调用这一步。

十六 }

这是方法体的结束大括号,标志着整个 checkAndStartInstallation 方法的逻辑到此结束。

——

结合以上的逐行分析,可以总结这段 Android 代码做了以下事情:

其一,判断当前系统版本是否大于等于 26,也就是是否在 Android 8.0 及以上。
其二,如果版本较高,检查应用是否具备安装未知来源应用的权限。若无权限,则设置一个等待授权的标志并跳转到某个页面让用户进行授权,随后直接 return 终止当前方法。
其三,如果已经有权限或者系统版本低于 26,就把等待授权的标志清空,然后开始正式的安装流程。

在实际的应用开发中,这样的逻辑对于分发渠道或企业内应用安装都非常常见。因为某些用户会从网页或第三方应用商店下载 APK,需要在安装时给予未知来源安装权限。如果没有在高版本 Android 系统里进行这一步检查,就会导致安装过程失败或报错。更糟糕的是,用户可能不知道如何在系统设置里找到相关选项。通过这段代码,开发者可以在检查到没有权限时,引导用户到正确的位置开启权限,从而提升用户体验。

再补充一些真实案例来说明为什么这个流程重要: 假设一家连锁餐饮企业为内部员工开发了一个排班管理 App,只在企业官网上提供下载。员工在自己的 Android 10 手机上下载好 APK 准备安装,结果发现系统提示需要先给该企业 App 授权“允许安装未知来源应用”。如果没有这段代码进行检查和引导,员工很可能会因为找不到系统权限入口而放弃安装,或频繁询问技术人员“要去哪里开启安装权限”。一旦有了这段逻辑,就可以自动跳转到系统的权限管理界面或者弹出合适的对话框,让员工直接勾选授权即可。返回应用后继续安装流程,大大减少了操作难度。

此外,写这段代码时,需要注意的一点是用户体验和错误处理。如果跳转到权限设置页面后,用户没有同意授权就返回了,或者根本没有找到对应的设置项,就会导致安装流程无法继续。开发者通常会在 onActivityResult 或者其他回调中再次检查 canRequestPackageInstalls,如果依然是 false,就提示用户再次尝试或给出更明确的指引。

另一个需要注意的细节是安全性。从 Android 8.0 开始,系统把未知来源应用的安装权限拆分到每一个请求安装的 App 中,这样可以更加细粒度地控制哪些应用可以安装外部来源的 APK,从而提升系统整体安全性。在早期版本中,系统只有一个“未知来源”开关,一旦打开后,所有应用都可以安装未知

有时开发者也会考虑到,如果用户点击“安装”按钮时没有权限,就弹出自定义对话框告诉用户为什么需要权限,然后再调用 startActivityForResult 跳转到权限设置页面。这在用户体验上会更加友好,也能避免用户被突然跳转的行为搞得不知所措。举例而言,如果企业 App 想让员工信任其来源,就可以在对话框里解释:“由于这是企业官方内部应用,请授予我们安装外部

综合来看,这段代码最核心的功能就是:
• 对系统版本进行判断,决定是否需要使用新的未知来源安装权限模式。
• 如果需要且尚未获取权限,就引导用户授权。
• 授权完成或无需授权时,就继续安装流程。

对于初学者而言,可能会好奇为什么要在 Android 8.0 上引入 canRequestPackageInstalls 这样的 API。原因在于 Google 希望给用户更多可控性,减少恶意应用在用户不知情的情况下自动安装,从而提高安全性。对于开发者而言,既要兼容较低版本的系统逻辑,又要适配新版本的权限要求,所以就出现了 if (i >= 26) 这样的判断分支。若没有进行这个判断,在低版本设备上调用相关 API 可能会报错或导致不兼容的问题。

当我们把这一切联系到真实案例中,能看出它对于应用分发、内部企业应用安装、第三方市场分发等场景都非常重要。一个企业内部应用若缺少这类检查,最终会给使用者带来困惑和不便,也可能造成大量售后咨询。一个想通过自己官网分发游戏的开发者,如果不做这类权限判断,用户在高版本系统上下载游戏后也无法顺利安装,导致大量流失或差评。由此可见,这段代码虽然短小,却起到承上启下的作用。

综上所述,这段 Android 代码完成的任务是: 依据系统版本和应用权限状态,判断是否需要跳转到权限设置或弹出相关对话框来请求安装未知来源应用的权限。若已经拥有权限或者系统版本不需要这项检查,则直接执行后续的安装流程。分步骤来看,每一行都在为这个目标服务: 先获取系统版本号,若版本较高则检查权限,没有就请求授权并记录等待状态,若已经拥有权限或者版本较低则直接清除等待状态并调用 proceedWithInstallation 继续安装。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号