Android基础(30)动态权限、安全

1)动态权限适配方案,权限组的概念

2)权限管理系统(底层的权限是如何进行 grant 的)?
http://www.cnblogs.com/rossoneri/p/10266189.html
3)谈谈你对安卓签名的理解。
4)App 是如何沙箱化,为什么要这么做?
https://blog.csdn.net/ljheee/article/details/53191397


5)请解释安卓为啥要加签名机制?

一. 简介

从Android6.0 棉花糖,Google进行了应用的权限申请方案。调整之后的用户授权,不仅仅体现在用户安装应用之时,更为重要的是,对于权限层级为危险的用户权限,需要在应用运行时向其授权,简称,动态授权

动态授权方案不仅可以简化应用安装过程,用户在安装或更新过程中可以不需要授予权限,而且更为重要的是可以实现用户对应用功能进行更多的控制,从而达到用户增强隐私的保护。

动态授权方案将系统权限进行了分级。分为危险权限和普通权限。危险权限需要在使用的地方,通过官方调用的API主动申请。

// 涉及读写联系人,访问账户
group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS
// 涉及电话操作
group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL
// 涉及日历信息的操作(用户日程安排)
group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR
// 涉及相机操作
group:android.permission-group.CAMERA
  permission:android.permission.CAMERA
// 涉及使用手机传感器操作
group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS
// 涉及用户地理位置信息的操作
group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION
// 涉及存储卡的读写操作
group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE
// 涉及多媒体信息的操作哦
group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO
// 涉及SMS卡的操作
group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

ungrouped:
  permission:com.xiaomi.xmsf.permission.PAYMENT // 小米 下载而不显示通知
  permission:miui.permission.ACCESS_BLE_SETTINGS  // 小米 涉及到用户设置的操作

二. 权限分类:
1.检查权限:ContextCompat.checkSelfPermission();

如果您的应用中需要危险权限,则每次执行需要这一权限的操作时,都必须检查是否具有该权限,用户始终可以自由的调用次权限,因此,即使应用昨天使用了并响应,他不能假设自己今天仍然具有该权限。

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);
2.申请权限:ContextCompat.requestPermissions();

如果应用需要Manifest清单中的危险权限,那么他必须要求用户授予该权限。并且在某些情况下,我们需要让用户了解应用为什么需要某些权限。最简单的例子是,当我们需要相机拍照的时候需要相机权限,这是很正常的需求,但是当我们需要保存照片信息的时候,需要用户的地理位置信息,这个权限对于用户来说就显得很不理解。针对这种现状,Google也为我们提供了很实用的Api ,ContextCompat.shouldShowRequestPermissionRationab-如果应用之前请求过次权限但用户拒绝了,则该方法返回true。如果用户不仅拒绝上次的请求权限,而且勾选了“不再提示”,则该方法返回false。


// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
 
    // Should we show an explanation?
    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
            Manifest.permission.READ_CONTACTS)) {
 
        // Show an expanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.
 
    } else {
 
        // No explanation needed, we can request the permission.
 
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
 
        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
        // app-defined int constant. The callback method gets the
        // result of the request.
    }
3.处理申请结果:onRequestPermissionResult();

当应用请求权限时候,系统将向用户显示一个对话框。当用户相应的时候,系统将调用onRequstPermissionsResult() 方法。向其传递用户的相应。我们需要在我们自己Activity中复写该方法。并且对用户操作的反馈做处理。

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted, yay! Do the
                // contacts-related task you need to do.
 
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }
 
        // other 'case' lines to check for other
        // permissions this app might request
    }
}
三. 实现

1.定义权限回调

    // 这是权限回调接口;
    public interface OnPermissionCallback {
        // 授权;
        void onGranted();
 
        // 拒绝;
        void onDenied();
    }

2.请求权限,这个是供外界调用的方法。参数为需要申请的权限,和权限回调。如果申请的权限已经被用户授权,则直接走授权回调,否则去申请权限。

 /**
   * 要求授权;
   */
    public void requestPermissions(@NonNull String[] permissions, @NonNull OnPermissionCallback
            callback) {
        if (permissions.length < 1) {
            return;
        }
        mPermissions = permissions;
        mPermissionCallback = callback;
        if (checkPermissions(permissions)) {
            // 有权限
            if (mPermissionCallback != null) {
                mPermissionCallback.onGranted();
            }
        } else {
            // 无权限;
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
        }
    }

3.申请权限后,程序会走OnRequestPermissionsResult()的回调。在回调中继续我们的逻辑;

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (checkPermissionResult(grantResults)) {
                // 全部授权
                if (mPermissionCallback != null) {
                    mPermissionCallback.onGranted();
                }
            } else {
                if (shouldShowRequestPermissionsRationale(permissions)) {
                    // 用户选择了拒绝;
                    ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
                } else {
                    // 用户选择了不再提示;
                    showPermissionRationale(null, null);
                }
                // 没有全部授权;
                if (mPermissionCallback != null) {
                    mPermissionCallback.onDenied();
                }
            }
 
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

在onRequestPermissionResult方法中,如果申请的所有权限都已经授权,则走授权回调。没有的话,再通过shouldRequestPermissionRationale()方法继续分析用户的针对我们的上次授权的操作。需要说明的一点是shouldRequestPermissonsRationale()这个方法的返回值,如果用户针对我们的上次请求权限拒绝的话,会返回true,如果用户针对我们的上次请求权限不仅做了拒绝的操作,而且还点击了“不再提醒”(就是以后不会再跳出授权框)的选择框,则该方法返回false。
针对这个情况,如果用户只是单纯的拒绝授权,我们在这里进行第二次的请求权限。如果用户选择“不再提醒”,我们就弹出一个自定的Dialog,引导用户去设置界面授权。

这里的Dialog,我直接用了SweetDialog的普通样式。

    // 跳出 提示界面;
    private void showPermissionRationale(@Nullable String title, @NonNull String content) {
        SweetAlertDialog dialog = new SweetAlertDialog(this, SweetAlertDialog.NORMAL_TYPE);
        dialog.setCancelable(false);
        dialog.setTitleText(TextUtils.isEmpty(title) ? getString(R.string.permission_title) : title)
                .setContentText(TextUtils.isEmpty(content) ? getString(R.string
                        .permission_content) : content)
                .setConfirmButton(R.string.dialog_ok, new SweetAlertDialog.OnSweetClickListener() {
                    @Override
                    public void onClick(SweetAlertDialog sweetAlertDialog) {
                        sweetAlertDialog.dismissWithAnimation();
                        gotoSetting();
                    }
                })
                .setCancelButton(R.string.permission_cancle, new SweetAlertDialog
                        .OnSweetClickListener() {
                    @Override
                    public void onClick(SweetAlertDialog sweetAlertDialog) {
                        sweetAlertDialog.dismissWithAnimation();
                        if(mPermissionCallback!=null){
                            mPermissionCallback.onDenied();
                        }
                    }
                })
                .show();
    }

在Dialog中如果用户选择取消的话,则表示这次授权失败了,直接走失败的回调。如果用户选择"ok”的话,则引导用户到设置详情界面去手动授权。

  // 跳转到设置界面;
    private void gotoSetting() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.fromParts("package", getPackageName(), null));
        startActivityForResult(intent, PERMISSION_REQUEST_CODE);
    }

需要注意的是这里引导用户到设置界面的方式是通过startActivityForResult()的方式。用户在从设置界面回到应用的时候,会走onActivityResult()方法,在这里我们需要再一次的对权限做判断。

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (mPermissions != null && checkPermissions(mPermissions)) {
                if (mPermissionCallback != null) {
                    mPermissionCallback.onGranted();
                } else {
                    mPermissionCallback.onDenied();
                }
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
 
    }

以上的这些都是在我的Activity的基类中完成的。我的所有activity继承这个基类。在需要动态权限的地方只需要一句代码就可以完成动态权限的申请了。

        requestPermissions(new String[]{Manifest.permission.CAMERA}, new OnPermissionCallback() {
            @Override
            public void onGranted() {
                Log.d("Permission","onGranted");
            }
 
            @Override
            public void onDenied() {
                Log.d("Permission","onDenied");
            }
        });
为什么需要android签名呢?
  1. 发送者的身份认证
    由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不同的包不被替换

  2. 保证信息传输的完整性
    签名对于包中的每个文件进行处理,以此确保包中内容不被替换

  3. 防止交易中的抵赖发生, Market 对软件的要求

给apk签名可以带来以下好处:
  1. 应用程序升级:如果你希望用户无缝升级到新的版本,那么你必须用同一个证书进行签名。这是由于只有以同一个证书签名,系统才会允许安装升级的应用程序。如果你采用了不同的证书,那么系统会要求你的应用程序采用不同的包名称,在这种情况下相当于安装了一个全新的应用程序。如果想升级应用程序,签名证书要相同,包名称要相同!

  2. 应用程序模块化:Android系统可以允许同一个证书签名的多个应用程序在一个进程里运行,系统实际把他们作为一个单个的应用程序,此时就可以把我们的应用程序以模块的方式进行部署,而用户可以独立的升级其中的一个模块

  3. 代码或者数据共享:Android提供了基于签名的权限机制,那么一个应用程序就可以为另一个以相同证书签名的应用程序公开自己的功能。以同一个证书对多个应用程序进行签名,利用基于签名的权限检查,你就可以在应用程序间以安全的方式共享代码和数据了。
    不同的应用程序之间,想共享数据,或者共享代码,那么要让他们运行在同一个进程中,而且要让他们用相同的证书签名。

怎样签名呢?用java自带的keytool和jarsigner工具。

  1. 通过以下命令可以获取证书和私钥:keytool -genkey -v -keystore doumiw.keystore -alias doumiw -keyalg RSA -validity 10000
  2. 通过以下命令可以对apk签名:jarsigner -verbose -keystore doumiw.keystore doumiw.apk doumiw
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容