android6.0系統允許用戶管理應用權限,可以關閉/打開權限。
所以需要在APP中增加權限判斷,以免用戶關閉相應權限后,APP運行異常。
以MMS為例,在系統設置——應用——MMS——權限——>關閉短信權限
這個界面的處理代碼在 android\packages\apps\PackageInstaller 中。
通過調試 PackageInstaller,可以知道短信權限對應是 permissionGroup: android.permission-group.SMS
其中包含的具體permission:
android.permission.READ_SMS,
android.permission.RECEIVE_WAP_PUSH,
android.permission.RECEIVE_MMS,
android.permission.RECEIVE_SMS,
android.permission.SEND_SMS,
android.permission.READ_CELL_BROADCASTS
關閉短信權限后,MMS無法讀取,收發信息。操作MMS還會出現報錯現象。所以需要在MMS啟動時增加權限判斷。
查看PackageInstaller中關閉權限的處理
AppOpsManager mAppOps = context.getSystemService(AppOpsManager.class);
......
// Disable the app op. mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_IGNORED); //將權限對應的操作標記為 AppOpsManager.MODE_IGNORED,使權限被限制
AppOpsManager 是專門管理 APP操作權限的, 所以用AppOpsManager來判斷權限是否被允許。
AppOpsManager中定義了系統權限對應的int碼,和string字符。可以直接拿來用
android\frameworks\base\core\java\android\app\AppOpsManager.java
/** @hide No operation specified. */ public static final int OP_NONE = -1; /** @hide Access to coarse location information. */ public static final int OP_COARSE_LOCATION = 0; /** @hide Access to fine location information. */ public static final int OP_FINE_LOCATION = 1; /** @hide Causing GPS to run. */ public static final int OP_GPS = 2; /** @hide */ public static final int OP_VIBRATE = 3; /** @hide */ public static final int OP_READ_CONTACTS = 4; /** @hide */ public static final int OP_WRITE_CONTACTS = 5; /** @hide */ public static final int OP_READ_CALL_LOG = 6; /** @hide */ public static final int OP_WRITE_CALL_LOG = 7; /** @hide */ public static final int OP_READ_CALENDAR = 8; /** @hide */ public static final int OP_WRITE_CALENDAR = 9; /** @hide */ public static final int OP_WIFI_SCAN = 10; /** @hide */ public static final int OP_POST_NOTIFICATION = 11; /** @hide */ public static final int OP_NEIGHBORING_CELLS = 12; /** @hide */ public static final int OP_CALL_PHONE = 13; /** @hide */ public static final int OP_READ_SMS = 14; /** @hide */ public static final int OP_WRITE_SMS = 15; /** @hide */ public static final int OP_RECEIVE_SMS = 16; /** @hide */ public static final int OP_RECEIVE_EMERGECY_SMS = 17; /** @hide */ public static final int OP_RECEIVE_MMS = 18; /** @hide */ public static final int OP_RECEIVE_WAP_PUSH = 19; /** @hide */ public static final int OP_SEND_SMS = 20; /** @hide */ public static final int OP_READ_ICC_SMS = 21; /** @hide */ public static final int OP_WRITE_ICC_SMS = 22; /** @hide */ public static final int OP_WRITE_SETTINGS = 23; /** @hide */ public static final int OP_SYSTEM_ALERT_WINDOW = 24; /** @hide */ public static final int OP_ACCESS_NOTIFICATIONS = 25; /** @hide */ public static final int OP_CAMERA = 26; /** @hide */ public static final int OP_RECORD_AUDIO = 27; /** @hide */ public static final int OP_PLAY_AUDIO = 28; /** @hide */ public static final int OP_READ_CLIPBOARD = 29; /** @hide */ public static final int OP_WRITE_CLIPBOARD = 30; /** @hide */ public static final int OP_TAKE_MEDIA_BUTTONS = 31; /** @hide */ public static final int OP_TAKE_AUDIO_FOCUS = 32; /** @hide */ public static final int OP_AUDIO_MASTER_VOLUME = 33; /** @hide */ public static final int OP_AUDIO_VOICE_VOLUME = 34; /** @hide */ public static final int OP_AUDIO_RING_VOLUME = 35; /** @hide */ public static final int OP_AUDIO_MEDIA_VOLUME = 36; /** @hide */ public static final int OP_AUDIO_ALARM_VOLUME = 37; /** @hide */ public static final int OP_AUDIO_NOTIFICATION_VOLUME = 38; /** @hide */ public static final int OP_AUDIO_BLUETOOTH_VOLUME = 39; /** @hide */ public static final int OP_WAKE_LOCK = 40; /** @hide Continually monitoring location data. */ public static final int OP_MONITOR_LOCATION = 41; /** @hide Continually monitoring location data with a relatively high power request. */ public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42; /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ public static final int OP_GET_USAGE_STATS = 43; /** @hide */ public static final int OP_MUTE_MICROPHONE = 44; /** @hide */ public static final int OP_TOAST_WINDOW = 45; /** @hide Capture the device's display contents and/or audio */ public static final int OP_PROJECT_MEDIA = 46; /** @hide Activate a VPN connection without user intervention. */ public static final int OP_ACTIVATE_VPN = 47; /** @hide Access the WallpaperManagerAPI to write wallpapers. */ public static final int OP_WRITE_WALLPAPER = 48; /** @hide Received the assist structure from an app. */ public static final int OP_ASSIST_STRUCTURE = 49; /** @hide Received a screenshot from assist. */ public static final int OP_ASSIST_SCREENSHOT = 50; /** @hide Read the phone state. */ public static final int OP_READ_PHONE_STATE = 51; /** @hide Add voicemail messages to the voicemail content provider. */ public static final int OP_ADD_VOICEMAIL = 52; /** @hide Access APIs for SIP calling over VOIP or WiFi. */ public static final int OP_USE_SIP = 53; /** @hide Intercept outgoing calls. */ public static final int OP_PROCESS_OUTGOING_CALLS = 54; /** @hide User the fingerprint API. */ public static final int OP_USE_FINGERPRINT = 55; /** @hide Access to body sensors such as heart rate, etc. */ public static final int OP_BODY_SENSORS = 56; /** @hide Read previously received cell broadcast messages. */ public static final int OP_READ_CELL_BROADCASTS = 57; /** @hide Inject mock location into the system. */ public static final int OP_MOCK_LOCATION = 58; /** @hide Read external storage. */ public static final int OP_READ_EXTERNAL_STORAGE = 59; /** @hide Write external storage. */ public static final int OP_WRITE_EXTERNAL_STORAGE = 60; /** @hide Turned on the screen. */ public static final int OP_TURN_SCREEN_ON = 61; /** @hide Get device accounts. */ public static final int OP_GET_ACCOUNTS = 62; /** @hide */ public static final int _NUM_OP = 63;
//--------------------------------上面的int 類型標記了@hide,需要在源碼下才能調用編譯通過。對於普通APP,可以用下面的string 類型-----------------------------//
/** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = "android:coarse_location"; /** Access to fine location information. */ public static final String OPSTR_FINE_LOCATION = "android:fine_location"; /** Continually monitoring location data. */ public static final String OPSTR_MONITOR_LOCATION = "android:monitor_location"; /** Continually monitoring location data with a relatively high power request. */ public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION = "android:monitor_location_high_power"; /** Access to {@link android.app.usage.UsageStatsManager}. */ public static final String OPSTR_GET_USAGE_STATS = "android:get_usage_stats"; /** Activate a VPN connection without user intervention. @hide */ @SystemApi public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; /** Allows an application to read the user's contacts data. */ public static final String OPSTR_READ_CONTACTS = "android:read_contacts"; /** Allows an application to write to the user's contacts data. */ public static final String OPSTR_WRITE_CONTACTS = "android:write_contacts"; /** Allows an application to read the user's call log. */ public static final String OPSTR_READ_CALL_LOG = "android:read_call_log"; /** Allows an application to write to the user's call log. */ public static final String OPSTR_WRITE_CALL_LOG = "android:write_call_log"; /** Allows an application to read the user's calendar data. */ public static final String OPSTR_READ_CALENDAR = "android:read_calendar"; /** Allows an application to write to the user's calendar data. */ public static final String OPSTR_WRITE_CALENDAR = "android:write_calendar"; /** Allows an application to initiate a phone call. */ public static final String OPSTR_CALL_PHONE = "android:call_phone"; /** Allows an application to read SMS messages. */ public static final String OPSTR_READ_SMS = "android:read_sms"; /** Allows an application to receive SMS messages. */ public static final String OPSTR_RECEIVE_SMS = "android:receive_sms"; /** Allows an application to receive MMS messages. */ public static final String OPSTR_RECEIVE_MMS = "android:receive_mms"; /** Allows an application to receive WAP push messages. */ public static final String OPSTR_RECEIVE_WAP_PUSH = "android:receive_wap_push"; /** Allows an application to send SMS messages. */ public static final String OPSTR_SEND_SMS = "android:send_sms"; /** Required to be able to access the camera device. */ public static final String OPSTR_CAMERA = "android:camera"; /** Required to be able to access the microphone device. */ public static final String OPSTR_RECORD_AUDIO = "android:record_audio"; /** Required to access phone state related information. */ public static final String OPSTR_READ_PHONE_STATE = "android:read_phone_state"; /** Required to access phone state related information. */ public static final String OPSTR_ADD_VOICEMAIL = "android:add_voicemail"; /** Access APIs for SIP calling over VOIP or WiFi */ public static final String OPSTR_USE_SIP = "android:use_sip"; /** Use the fingerprint API. */ public static final String OPSTR_USE_FINGERPRINT = "android:use_fingerprint"; /** Access to body sensors such as heart rate, etc. */ public static final String OPSTR_BODY_SENSORS = "android:body_sensors"; /** Read previously received cell broadcast messages. */ public static final String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts"; /** Inject mock location into the system. */ public static final String OPSTR_MOCK_LOCATION = "android:mock_location"; /** Read external storage. */ public static final String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage"; /** Write external storage. */ public static final String OPSTR_WRITE_EXTERNAL_STORAGE = "android:write_external_storage"; /** Required to draw on top of other apps. */ public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window"; /** Required to write/modify/update system settingss. */ public static final String OPSTR_WRITE_SETTINGS = "android:write_settings"; /** @hide Get device accounts. */ public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
檢查權限方法
public int checkOp(String op, int uid, String packageName) { return checkOp(strOpToOp(op), uid, packageName); //strOpToOp(op)將string碼轉為int碼,相當於調用checkOp(int op, int uid, String packageName)
//checkOp(int op, int uid, String packageName)是@hide的,所以只有源碼環境下才能直接調用,編譯。
}
下面是我寫的MMS中檢查權限的方法。
public static void mmsPermissionCheck(Context context){ final String smsPermissionGroupName = "android.permission-group.SMS"; final Handler handler = new Handler(); final Context mContext = context; final Runnable showPermissonCheck = new Runnable() { public void run() { new AlertDialog.Builder(mContext) .setMessage(mContext.getString(R.string.check_mms_permission)) .setPositiveButton(android.R.string.ok, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { ((Activity)mContext).finish(); } }) .setCancelable(false) .create().show(); } }; PackageManager pm = context.getPackageManager(); AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); //AppOpsManager 用來判斷權限 try { PackageInfo pkgInfo = pm.getPackageInfo(context.getPackageName(),PackageManager.GET_PERMISSIONS); for(PermissionGroupInfo permissionGroupInfo : pm.getAllPermissionGroups(0) ){ Log.i("antoon", permissionGroupInfo.name); } /** * permissionGroup: android.permission-group.SMS * permission: android.permission.READ_SMS, android.permission.RECEIVE_WAP_PUSH, * android.permission.RECEIVE_MMS, android.permission.RECEIVE_SMS, * android.permission.SEND_SMS, android.permission.READ_CELL_BROADCASTS * if permission denied, appOpsManager.checkOp(...) will return >=1 */ int resultCount = 0; for(PermissionInfo permissionInfo : pm.queryPermissionsByGroup(smsPermissionGroupName,0) ){ Log.i("antoon", permissionInfo.name); int appOp = AppOpsManager.permissionToOpCode(permissionInfo.name); int result = appOpsManager.checkOp(appOp, pkgInfo.applicationInfo.uid, pkgInfo.packageName); Log.e("antoon", "result = " + result); resultCount += result; } if(resultCount > 1){ handler.post(showPermissonCheck); } } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } }