You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

已构建APK权限失效:仅开发设备可用,其他设备报权限缺失与安全异常

解决APK仅能在开发设备运行的权限与Security Exception问题

嘿,我帮你梳理下这个问题的核心原因和解决办法:你的应用在开发手机能跑,其他设备报错,大概率是权限处理不规范导致的——毕竟Android 6.0之后对危险权限的管控严格了很多,开发机可能因为调试环境自动获取了权限,其他设备没这个待遇。

一、核心问题:危险权限未做动态申请

你Manifest里声明的这些权限大多属于Android的危险权限CALL_PHONESEND_SMSACCESS_FINE_LOCATIONREAD_CONTACTS等等。这类权限不能只在Manifest里写就完事,必须在应用运行时主动向用户申请,用户同意后才能使用。开发机上你可能之前手动给过权限,或者调试模式下默认授权了,但其他设备没有这个过程,自然会触发权限不可用和Security Exception。

二、分步解决办法

1. 给危险权限添加动态申请逻辑

在应用启动的第一个Activity(比如你的WelcomeActivity)里加入权限检查和申请的代码,确保用户授权后再进入核心功能:

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class Welcome extends AppCompatActivity {
    // 定义需要申请的所有危险权限
    private static final String[] REQUIRED_PERMISSIONS = {
        Manifest.permission.CALL_PHONE,
        Manifest.permission.SEND_SMS,
        Manifest.permission.READ_SMS,
        Manifest.permission.WRITE_SMS,
        Manifest.permission.RECEIVE_SMS,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.READ_CONTACTS,
        Manifest.permission.WRITE_CONTACTS
    };
    private static final int PERMISSION_REQUEST_CODE = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        // 启动时检查权限,没授权就申请
        if (!hasAllPermissions()) {
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, PERMISSION_REQUEST_CODE);
        }
    }

    // 检查是否所有权限都已授予
    private boolean hasAllPermissions() {
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    // 处理权限申请结果
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            boolean allGranted = true;
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }
            if (!allGranted) {
                Toast.makeText(this, "必须开启所有必要权限才能使用应用,请在设置中授权", Toast.LENGTH_LONG).show();
                // 这里可以选择退出应用,或者引导用户跳转到权限设置页
            }
        }
    }
}

2. 修复INSTALL_SHORTCUT权限的兼容性问题

com.android.launcher.permission.INSTALL_SHORTCUT这个权限在很多第三方Launcher和高版本Android里已经不兼容了,建议换成Android 8.0及以上支持的ShortcutManager API来创建桌面快捷方式,同时可以移除Manifest里这个过时的权限:

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;

public class Welcome extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        // 创建桌面快捷方式的兼容代码
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
                Intent shortcutIntent = new Intent(this, Welcome.class);
                shortcutIntent.setAction(Intent.ACTION_MAIN);

                ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(this, "panic_button_shortcut")
                        .setIntent(shortcutIntent)
                        .setShortLabel("Panic Button")
                        .setIcon(IconCompat.createWithResource(this, R.drawable.welcome))
                        .build();

                ShortcutManagerCompat.requestPinShortcut(this, shortcutInfo, null);
            }
        }
    }
}

3. 在敏感操作处捕获异常

调用打电话、发短信、获取位置这些需要权限的功能时,记得加try-catch捕获Security Exception,避免应用直接崩溃,同时给用户友好提示:

// 示例:打电话的代码
private void makeEmergencyCall(String phoneNumber) {
    try {
        Intent callIntent = new Intent(Intent.ACTION_CALL);
        callIntent.setData(Uri.parse("tel:" + phoneNumber));
        startActivity(callIntent);
    } catch (SecurityException e) {
        Toast.makeText(this, "没有打电话的权限,请先在设置中开启", Toast.LENGTH_SHORT).show();
        e.printStackTrace();
    }
}

4. 确保安装与签名正常

如果是给其他设备安装debug包,需要确保设备允许安装未知来源应用(Android 8.0及以上是单独允许该应用的安装权限);如果是正式测试,建议用release签名的APK,避免debug签名导致的信任问题。


内容的提问来源于stack exchange,提问作者Dhanasekar B

火山引擎 最新活动