您的位置:首页 > 移动开发 > Android开发

Android M版本和非M版本动态权限适配方案---续篇

2016-05-11 21:16 447 查看
在我上一篇文章中介绍了一下Android M版本与非M版本的动态权限适配的方案,只介绍了一个大体思路。

详细的可以看Android M版本和非M版本动态权限适配方案。

这篇文章主要介绍一下该方案的实现。

1. 控制权限申请的入口和出口,将动态权限的出口和入口唯一化,降低动态权限对原来老版本代码的冲击,避免大面积重构代码。

整个方案职能图如下:



2、PermissionsManager核心代码:

/**
     * 权限申请回调函数
     *
     */
    public interface PermissionsResultsCallback
    {
        void onRequestPermissionsResult(int[] grantResults);
    }

    /** 请求权限CodeId对应到具体的每一次申请*/
    private int mRequestCodeId;

    /** 每一次申请对应回调函数*/
    private final Map<Integer, PermissionsResultsCallback> mRequestIdToCallback = new HashMap<Integer, PermissionsResultsCallback>();

    /** 每一次申请对应的权限表*/
    private final Map<Integer, Map<String, Integer>> mRequestIdToPermissions = new HashMap<Integer, Map<String, Integer>>();
    
    /** 当前请求权限*/
    private final Map<String, Integer> mWaitingRequestPermissions = new HashMap<String, Integer>();

/**
* 新的请求权限方法,在内部处理M版本和非版本的适配, 同时也是PermissionsManager动态权限申请的入口
*
* @param callback 回调函数,回调申请权限的string数组对应的状态(有权限或没有权限)
* @param activity
* @param permissionsToRequest
*/
public synchronized void newRequestPermissions(PermissionsResultsCallback callback, Activity activity,
String... permissionsToRequest)
{
// 初始化申请权限状态表
Map<String, Integer> map = PermissionsUtil.getStatusPermissions(mApplicationContext, permissionsToRequest);
// 筛选出未获取用户授权的申请权限数组
String[] permissionsArray = PermissionsUtil.arrayDeniedPermissions(map);
// 分配申请Id给本次权限申请
int requestId = getNextRequestId();

LogC.i("requestPermissions, requestId:" + requestId, false);
// 存储本次申请授权的回调函数和权限状态表
mRequestIdToCallback.put(requestId, callback);
mRequestIdToPermissions.put(requestId, map);

permissionsArray = getDeniedOrRequestingPermissions(permissionsArray);

// 判断当申请权限全部为已授权时,直接回调
if (null == permissionsArray || permissionsArray.length == 0)
{
// 当前权限申请正在进行
LogC.i("PermissionsManager permissionsArray has a permission requesting or null", false);
onRequestPermissionsResult(requestId, permissionsArray, new int[0]);
return;
}
else
{
for (String permission : permissionsArray)
{
// 当前权限申请未正在进行
LogC.i("PermissionsManager permission === "+permission+" is requesting", false);
mWaitingRequestPermissions.put(permission,requestId);
}
}

// 判断当有申请权限为未授权时,执行权限申请操作
if (null != activity)
{
LogC.i("PermissionsManager requestPermissions startActivityForResult", false);
Intent intent = new Intent(activity, PermissionsActivity.class);
intent.putExtra(PermissionsActivity.EXTRA_PERMISSION_REQUESTED_PERMISSIONS, permissionsArray);
intent.putExtra(PermissionsActivity.EXTRA_PERMISSION_REQUEST_CODE, requestId);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
activity.startActivityForResult(intent, REQUEST_CODE);
}
else
{
// 默认情况下申请权限方式
LogC.i("PermissionsActivity.run(mApplicationContext, requestId, permissionsArray)", false);
PermissionsActivity.run(mApplicationContext, requestId, permissionsArray);
}
}

/**
     * 回调函数,回调每次申请权限的处理接口 同时PermissionsManager动态权限申请的出口
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public synchronized void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {
        LogC.i("PermissionsManager onRequestPermissionsResult, requestCode:" + requestCode, false);
        // 解析权限申请结果,将权限结果状态更新到权限状态表
        Map<String, Integer> map = mRequestIdToPermissions.get(requestCode);
        if (null != map)
        {
            // 再次检测刷新申请权限的状态
            map = PermissionsUtil.getStatusPermissions(mApplicationContext, map);
            for (int i = 0; i < grantResults.length; i++)
            {
                map.put(permissions[i], grantResults[i]);
            }
            grantResults = PermissionsUtil.arrayStatusPermissions(map);
            
            for (String permission : map.keySet())
            {
                if(mWaitingRequestPermissions.containsKey(permission) && requestCode == mWaitingRequestPermissions.get(permission))
                {
                    LogC.i("PermissionsManager key === "+ permission +" remove !", false);
                    mWaitingRequestPermissions.remove(permission);
                }
            }
        }
        // 将权限状态回调给本次申请的回调函数
        PermissionsResultsCallback permissionsResultsCallback = mRequestIdToCallback.get(requestCode);
        if (null == permissionsResultsCallback)
        {
            LogC.i("onRequestPermissionsResult permissionsResultsCallback null", false);
        }
        else
        {
            // 删除本次权限申请的回调和状态表
            LogC.i("callback remove:" + mRequestIdToCallback.remove(requestCode), false);
            LogC.i("requestMap remove:" + mRequestIdToPermissions.remove(requestCode), false);
            permissionsResultsCallback.onRequestPermissionsResult(grantResults);
        }
    }


3、PermissionsActivity核心代码

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
sp = getApplicationContext().getSharedPreferences(PERMISSION_CACHE_NAME, Context.MODE_PRIVATE);
LogC.i("permissions check onCreate", false);
mPendingRequestCode = (savedInstanceState != null) ? savedInstanceState.getInt(EXTRA_PERMISSION_REQUEST_CODE,
INVALID_REQUEST_CODE) : INVALID_REQUEST_CODE;
}

@Override
protected void onResume()
{
super.onResume();
// 当请求码为默认值时执行
if (mPendingRequestCode == INVALID_REQUEST_CODE)
{
Intent intent = getIntent();
Bundle extras = null;
if (null != intent)
{
extras = getIntent().getExtras();
}
if (null != extras)
{
final String[] permissionsToRequest = extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS);
mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE);
// 判断用户是否之前有拒绝权限申请且勾选了不再提醒选项
if (!PermissionsUtil.isShouldShowRequestPermissionRationale(this, permissionsToRequest)
&& !isHaveFirstRequestPermission(permissionsToRequest))
{
showPermissionDialog(PermissionsActivity.this, mPendingRequestCode, permissionsToRequest);
}
else
{
requestPermissions(permissionsToRequest,mPendingRequestCode);
}
}
}
}

/**
     *
     * 引导进入应用权限管理页面的dialog
     *
     * @param activity
     * @param permissionsToRequest
     */
    private void showPermissionDialog(final Activity activity, final int mPendingRequestCode,
            String[] permissionsToRequest)
    {
        AlertDialog.Builder builder = new Builder(this);
        AlertDialog dialog = null;
        StringBuilder sb = new StringBuilder(getString(R.string.permissions_tips));
        for (int i = 0; i < permissionsToRequest.length; i++)
        {
            sb.append("\n");
            Integer key = PermissionsUtil.PERMISSION_TIPS.get(permissionsToRequest[i]);
            if (null != key)
            {
                String tip = getString(key);
                sb.append(tip);
            }
        }
        builder.setMessage(sb.toString());
        builder.setTitle(getString(R.string.huaweipay_note));
        builder.setPositiveButton(getString(R.string.go_settings), new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                // 打开权限管理器的应用授权activity
                openManangePermissionUI(activity, mPendingRequestCode);
                dialog.dismiss();
            }
        });
        builder.setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                dialog.dismiss();
                // 直接回调结果给Permissionsmanager,String[0],int[0]表示本次对于权限无任务修改
                onRequestPermissionsResult(mPendingRequestCode, new String[0], new int[0]);
            }
        });
        dialog = builder.create();
        dialog.setOnKeyListener(new DialogInterface.OnKeyListener()
        {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event)
            {
                if (keyCode == KeyEvent.KEYCODE_BACK)
                {
                    dialog.dismiss();
                    // 直接回调结果给Permissionsmanager,String[0],int[0]表示本次对于权限无任务修改
                    onRequestPermissionsResult(mPendingRequestCode, new String[0], new int[0]);
                }
                return false;
            }

        });
        dialog.setCanceledOnTouchOutside(false);
        dialog.show();
    }

    /**
     *
     * 调起系统应用的权限管理页面,依赖与android.permission.GRANT_RUNTIME_PERMISSIONS权限(
     * 正式平台签名apk才会授予)若自身应用没有平台权限,建议引导用户跳转到setting页面即可
     *
     */
    public void openManangePermissionUI(Activity activity, int mPendingRequestCode)
    {
        if (null == activity)
        {
            LogC.w("openManangePermissionUI activity is null ", false);
            return;
        }
        try
        {
            Intent intent = new Intent("android.intent.action.MANAGE_APP_PERMISSIONS");
            intent.putExtra("android.intent.extra.PACKAGE_NAME", activity.getPackageName());
            // 屏蔽掉权限管理页面右上角的应用详情按钮
            intent.putExtra("hideInfoButton", true);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            // 使用startActivityForResult,避免权限管理器操作未完成,而权限申请结果已回调
            activity.startActivityForResult(intent, mPendingRequestCode);
        }
        catch (ActivityNotFoundException e)
        {
            LogC.w("start action android.intent.action.MANAGE_APP_PERMISSIONS ActivityNotFoundException error", false);
            onRequestPermissionsResult(mPendingRequestCode, new String[0], new int[0]);
        }
        catch (SecurityException ee)
        {
            LogC.w("start action android.intent.action.MANAGE_APP_PERMISSIONS java.lang.SecurityException==Permission Denial error", false);
            onRequestPermissionsResult(mPendingRequestCode, new String[0], new int[0]);
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        // 回调权限管理器的处理结果
        onRequestPermissionsResult(requestCode, new String[0], new int[0]);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
    {

        LogC.i(" permission activity onRequestPermissionsResult ", false);
        mPendingRequestCode = INVALID_REQUEST_CODE;
        setPermissionCache(permissions, true);
        finish();
        PermissionsManager.getInstance().onRequestPermissionsResult(requestCode, permissions, grantResults);

    }


注:对于动态权限,建议应用可以区分一下哪些是必要权限和哪些是非必要权限,比如读写sd卡这个权限完全是非必要的,在Android4.4之后,访问自身应用在sd卡的私有路径不需要任何权限(manifest中都不要去声明),对于非必要权限,可以允许用户继续操作,必要权限被拒绝,可以直接退出,避免处理太多的异常场景。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: