編輯:關於Android編程
Android
權限系統是一個非常重要的安全問題,因為它只有在安裝時會詢問一次。一旦軟件本安裝之後,應用程序可以在用戶毫不知情的情況下使用這些權限來獲取所有的內容。
很多壞蛋會通過這個安全缺陷來收集用戶的個人信息並使用它們來做壞事的情況就不足為奇了。
Android
團隊也意識到了這個問題。在經過了7年後,權限系統終於被重新設置了。從Anroid 6.0(API Level 23)
開始,應用程序在安裝時不會被授予任何權限,取而代之的是在運行時應用回去請求用戶授予對應的權限。這樣可以讓用戶能更好的去控制應用功能。例如,一個用戶可能會同一個拍照應用使用攝像頭的權限,但是不同授權它獲取設備位置的權限。用戶可以在任何時候通過去應用的設置頁面來撤銷授權。
vcDgo6w8Y29kZT5ub3JtYWw8L2NvZGU+us08Y29kZT5kYW5nZXJvdXM8L2NvZGU+OjwvcD4NCjxjb2RlPk5vcm1hbCBQZXJtaXNzaW9uczwvY29kZT6yu9Do0qrTw7un1rG908rayKijrMjnufvE47XE06bTw9Tax+W1pc7EvP7W0Mn5w/fBy05vcm1hbCBQZXJtaXNzaW9uc2CjrM+1zbO74dfUtq/K2siouMPIqM/eoaMgPGNvZGU+RGFuZ2Vyb3VzIFBlcm1pc3Npb25zPC9jb2RlPr/J0tTIw9Om08O78cih08O7p7XEy73Iy8r9vt2ho8jnufvE47XE06bTw9Tax+W1pc7EvP7W0Mnqx+vByzxjb2RlPkRhbmdlcm91cyBQZXJtaXNzaW9uczwvY29kZT6jrMTHvs2x2NDr0qrTw7unwLTK2siouPjTptPDoaMNCjxwPjxjb2RlPk5vcm1hbCBQZXJtaXNzaW9uczwvY29kZT46PGJyIC8+DQo8Y29kZT5Ob3JtYWwgUGVybWlzc2lvbjwvY29kZT7Kx7Wx08O7p7Cy17C78rj80MLTptPDyrGjrM+1zbO9q8ra0+jTptPDy/nH68fztcTIqM/eo6zT1rPGzqo8Y29kZT5QUk9URUNUSU9OX05PUk1BTDwvY29kZT6jqLCy17DKscrayKi1xNK7wOC7+bG+yKjP3qOpoaO4w8DgyKjP3ta70OjSqtTaPGNvZGU+bWFuaWZlc3Q8L2NvZGU+zsS8/tbQyfnD97y0v8mjrLCy17DKsb7NytrIqKOssrvQ6NKqw7+0zsq508PKsb340NC87LLpo6y2+MfS08O7p7K7xNzIoc/70tTJz8rayKihozwvcD4NCkFDQ0VTU19MT0NBVElPTl9FWFRSQV9DT01NQU5EUyBBQ0NFU1NfTkVUV09SS19TVEFURSBBQ0NFU1NfTk9USUZJQ0FUSU9OX1BPTElDWSBBQ0NFU1NfV0lGSV9TVEFURSBCTFVFVE9PVEggQkxVRVRPT1RIX0FETUlOIEJST0FEQ0FTVF9TVElDS1kgQ0hBTkdFX05FVFdPUktfU1RBVEUgQ0hBTkdFX1dJRklfTVVMVElDQVNUX1NUQVRFIENIQU5HRV9XSUZJX1NUQVRFIERJU0FCTEVfS0VZR1VBUkQgRVhQQU5EX1NUQVRVU19CQVIgR0VUX1BBQ0tBR0VfU0laRSBJTlNUQUxMX1NIT1JUQ1VUIElOVEVSTkVUIEtJTExfQkFDS0dST1VORF9QUk9DRVNTRVMgTU9ESUZZX0FVRElPX1NFVFRJTkdTIE5GQyBSRUFEX1NZTkNfU0VUVElOR1MgUkVBRF9TWU5DX1NUQVRTIFJFQ0VJVkVfQk9PVF9DT01QTEVURUQgUkVPUkRFUl9UQVNLUyBSRVFVRVNUX0lHTk9SRV9CQVRURVJZX09QVElNSVpBVElPTlMgUkVRVUVTVF9JTlNUQUxMX1BBQ0tBR0VTIFNFVF9BTEFSTSBTRVRfVElNRV9aT05FIFNFVF9XQUxMUEFQRVIgU0VUX1dBTExQQVBFUl9ISU5UUyBUUkFOU01JVF9JUiBVTklOU1RBTExfU0hPUlRDVVQgVVNFX0ZJTkdFUlBSSU5UIFZJQlJBVEUgV0FLRV9MT0NLIFdSSVRFX1NZTkNfU0VUVElOR1MNCjxwPs/CzbzOqjxjb2RlPkRhbmdlcm91cyBwZXJtaXNzaW9ucyBhbmQgcGVybWlzc2lvbiBncm91cHM8L2NvZGU+OjwvcD4NCjxwPjxpbWcgYWx0PQ=="image" src="/uploadfile/Collfiles/20160616/20160616090644102.png" title="\" />
在所有的Android
版本中,你的應用都需要在manifest
文件中聲明normal
和dangerous
權限。然而聲明所影響的效果會因系統版本和你應用的target SDK lever
有關:
Android 5.1
或者之前的系統,或者應用的targetSdkVersion
是22或者之前版本:如果你在manifest
中聲明了dangerous permission
,用戶需要在安裝應用時授權這些權限。如果用戶不授權這些權限,系統就不會安裝該應用。(我試了下發現即使targetSdkVersion
是22及以下,在6.0的手機上時,如果你安裝時你不同意一些權限,也仍然可以安裝的) 如果設備運行的是Android 6.0
或者更高的系統,並且你應用的targetSdkVersion
是23或者更高:應用必須在manifest
文件中申請這些權限,而且必須要在運行時對所需要的dangerous permission
申請授權。用戶可以統一或者拒絕授權,並且及時用戶拒絕了授權,應用在無法使用一些功能的情況下也要保證能繼續運行。
也就是說新的運行時權限僅當我們設置targetSdkVersion
是23及以上時才會起作用。
如果你的targtSdkVersion
低於23,那將被認為該應用沒有經過android 6.0
的測試,當該應用被安裝到了6.0的手機上時,仍然會使用之前的舊權限規則,在安裝時會提示所有需要的權限(這樣做是有道理的,不然對於之前開發的應用,我們都要立馬去修改讓它適應6.0,來不及的話就導致6.0的手機都無法使用了,顯然Android開發團隊不會考慮不到這種情況),當然用戶可以在安裝的界面不允許一些權限,那當程序使用到了這些權限時,會崩潰嗎?答案是在Android 6.0
及以上的手機會直接crash
,但是在23
之前的手機上不會crash
。
所以如果你的應用沒有支持運行時權限的功能,那千萬不要講targetSdkVersion
設置為23,否則就麻煩了。
注意:從
Android 6.0(API Level 23)
開始,即使應用的targetSdkVersion
是比較低的版本,但是用戶仍然可以在任何時候撤銷對應用的授權。所以不管應用的targetSdkVerison
是什麼版本,你都要測試你的應用在不能獲取權限時能不能正常運行。
下面介紹下如何使用Android Support Library
來檢查和請求權限。Android
框架在6.0
開始也提供了相同的方法。然而使用support
包會比較簡單,因為這樣你就不需要在請求方法時判斷當前的系統版本。(後面說的這幾個類都是android.support.v4
中的)
如果應用需要使用dangerous permission
,在任何時候執行需要該權限的操作時你都需要檢查是否已經授權。用戶可能會經常取消授權,所以即使昨天應用已經使用了攝像頭,這也不能保證今天仍然有使用攝像頭的權限。
為了檢查是否可以使用該權限,調用ContextCompat.checkSelfPermission()
。
例如:
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
如果應用有該權限,該方法將返回PackageManager.PERMISSION_GRANTED
,應用可以進行相關的操作。如果應用不能使用該權限,該方法將返回PERMISSION_DENIED
,這是應用將必須要向用戶申請該權限。
如果應用需要使用清單文件中申明的dangerous permission
,它必須要向用戶申請來授權。Android
提供了幾種申請授權的方法。使用這些方法時將會彈出一個標准的系統對話框,該對話框不能自定義。
在一些情況下,你可能需要幫助用力理解為什麼需要該權限。例如,一個用戶使用了一個照相的應用,用戶不會奇怪為什麼應用申請使用攝像頭的權限,但是用戶可能會不理解為什麼應用需要獲取位置或者聯系人的權限。在請求一個權限之前,你需要該用戶一個說明。一定要切記不要通過說明來壓倒用戶。如果你提供了太多的說明,用戶可能會感覺沮喪並且會卸載它。
一個你需要提供說明的合適時機就是在用戶之前已經不同意授權該權限的情況下。如果一個用戶繼續嘗試使用需要權限的功能時,但是之前確禁止了該權限的請求,這就可能是因為用戶不理解為什麼該功能需要使用該權限。在這種情況下,提供一個說明是非常合適的。
為了能找到用戶可能需要說明的情況,android
提供了一個工具類方法ActivityCompat.shouldShowRequestPermissionRationale().
。如果應用之前申請了該權限但是用戶拒絕授權後該方法會返回true
。(在Android 6.0之前調用的時候會直接返回false)
注意:如果用戶之前拒絕了權限申請並且選擇了請求權限對話框中的
Don’t ask again
選項,該方法就會返回false
。如果設備策略禁止了該應用使用該權限,該方法也會返回false
。(我測試的時候發現請求權限的對話框中並沒有Don’t asdk again
這一項)
如果應用沒有所需的權限時,應用必須調用ActivityCompat.requestPermissions (Activity activity,
方法來申請對用的權限。參數傳遞對應所需的權限以及一個整數型的
String[] permissions,
int requestCode)request code
來標記該權限申請。 該方法是異步的:該方法會立即返回,在用戶響應了請求權限的對話框之後,系統會調用對用的回調方法來通知結果,並且會傳遞在reqeustPermissions()
方法中的request code
。(在Android 6.0之前調用的時候會直接去調用onRequestPermissionsResult()
的回調方法)
如圖:
下面是檢查是否讀取聯系人權限,並且在必要時申請權限的代碼:
// 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.
}
}
注意:當調用
requestPermissions()
方法時,系統會顯示一個標准的對話框。應用不能指定或者改變該對話框。如果你想提供一些信息或者說明給用戶,你需要在調用requestPermissions()
之前處理。
如果應用申請權限,系統會顯示一個對話框。當用戶相應後,系統會調用應用中的onRequestPermissionsResult (int requestCode,
方法並傳遞用戶的操作結果。在應用中必須要重寫該方法來查找授權了什麼權限。該回調方法會傳遞你在
String[] permissions,
int[] grantResults)requestPermisssions()
方法中傳遞的request code
。直接在Activity
或者Fragment
中重寫onRequestPermissionsResult()
方法即可。例如,申請READ_CONTACTS
的權限可能會有下面的回到方法:
@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
}
}
系統提示的對話框會描述應用所需的permission groud
。它不會列出特定的權限。例如,如果你申請了READ_CONTACTS
權限,系統的對話框只會說你的應用需要獲取設備的聯系人信息。用戶只需要授權每個permission group
一次。如果你應用需要申請其他任何一個在該permission group
中的權限時,系統會自動授權。在申請這些授權時,系統會像用戶明確通過系統對話框統一授權時一樣去調用onRequestPermissionsResult()
方法並且傳遞PERMISSION_GRANTED
參數。
注意:雖然用戶已經授權了同一
permission group
中其他的任何權限,但是應用仍然需要明確申請每個需要的權限。例外,permission group
中的權限在以後可能會發生變化。
例如,假設在應用的manifest
文件中同時聲明了READ_CONTACTS
和WRITE_CONTACTS
權限。如果你申請READ_CONTACTS
權限而且用戶同意了該權限,如果你想繼續申請WRITE_CONTACTS
權限,系統不會與用戶有任何交互就會直接進行授權。
如果用戶拒絕了一個權限申請,你的應用進行合適的處理。例如,你的應用可能顯示一個對話框來表明無法執行用戶請求的需要該權限的操作。
如果系統向用戶申請權限授權,用戶選擇了讓系統以後不要再申請該權限。 在這種情況下,應用在任何時間調用reqeustPermissions()
方法來再次申請權限時,系統都會直接拒絕該請求。系統會直接調用onRequestPermissionResult()
回調方法並且傳遞PERMISSION_DENIED
參數,和用戶明確拒絕應用申請該權限時一樣。 這就意味著在你調用requestPermissions()
方法是,你無法確定是否會和用戶有直接的交互操作。
示例代碼:
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
private void insertDummyContactWrapper() {
List permissionsNeeded = new ArrayList();
final List permissionsList = new ArrayList();
if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
permissionsNeeded.add("GPS");
if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
permissionsNeeded.add("Read Contacts");
if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
permissionsNeeded.add("Write Contacts");
if (permissionsList.size() > 0) {
if (permissionsNeeded.size() > 0) {
// Need Rationale
String message = "You need to grant access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
showMessageOKCancel(message,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
}
});
return;
}
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
return;
}
insertDummyContact();
}
private boolean addPermission(List permissionsList, String permission) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
上面講到的都是Activity
中的使用方法,那Fragment
中怎麼授權呢?
如果在Fragment
中使用,用v13
包中的FragmentCompat.requestPermissions()
和FragmentCompat.shouldShowRequestPermissionRationale()
。
在Fragment
中申請權限,不要使用ActivityCompat.requestPermissions
, 直接使用Fragment.requestPermissions
方法,
否則會回調到Activity
的onRequestPermissionsResult
。但是雖然你使用Fragment.requestPermissions
方法,也照樣回調不到Fragment.onRequestPermissionsResult
中。這是Android
的Bug
,詳見,Google
已經在23.3.0
修復了該問題,所以要盡快升級。
所以升級到23.3.0
及以上就沒問題了。如果不升級該怎麼處理呢?就是在Activity.onRequestPermissionsResult
方法中去手動調用每個Fragment
的方法(當然你要判斷下權限個數,不然申請一個權限的情況下會重復調用).
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
List fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
我簡單的寫了一個工具類:
public class PermissionUtil {
/**
* 在調用需要權限的功能時使用該方法進行檢查。
*
* @param activity
* @param requestCode
* @param iPermission
* @param permissions
*/
public static void checkPermissions(Activity activity, int requestCode, IPermission iPermission, String... permissions) {
handleRequestPermissions(activity, requestCode, iPermission, permissions);
}
public static void checkPermissions(Fragment fragment, int requestCode, IPermission iPermission, String... permissions) {
handleRequestPermissions(fragment, requestCode, iPermission, permissions);
}
public static void checkPermissions(android.app.Fragment fragment, int requestCode, IPermission iPermission, String... permissions) {
handleRequestPermissions(fragment, requestCode, iPermission, permissions);
}
/**
* 在Actvitiy或者Fragment中重寫onRequestPermissionsResult方法後調用該方法。
*
* @param activity
* @param requestCode
* @param permissions
* @param grantResults
* @param iPermission
*/
public static void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions,
int[] grantResults, IPermission iPermission) {
requestResult(activity, requestCode, permissions, grantResults, iPermission);
}
public static void onRequestPermissionsResult(Fragment fragment, int requestCode, String[] permissions,
int[] grantResults, IPermission iPermission) {
requestResult(fragment, requestCode, permissions, grantResults, iPermission);
}
public static void onRequestPermissionsResult(android.app.Fragment fragment, int requestCode, String[] permissions,
int[] grantResults, IPermission iPermission) {
requestResult(fragment, requestCode, permissions, grantResults, iPermission);
}
public static void requestPermission(T t, int requestCode, String... permission) {
List permissions = new ArrayList<>();
for (String s : permission) {
permissions.add(s);
}
requestPermissions(t, requestCode, permissions);
}
/**
* 在檢查權限後自己處理權限說明的邏輯後調用該方法,直接申請權限。
*
* @param t
* @param requestCode
* @param permissions
* @param
*/
public static void requestPermission(T t, int requestCode, List permissions) {
if (permissions == null || permissions.size() == 0) {
return;
}
requestPermissions(t, requestCode, permissions);
}
public static boolean checkSelfPermission(Context context, String permission) {
if (context == null || TextUtils.isEmpty(permission)) {
throw new IllegalArgumentException("invalidate params: the params is null !");
}
context = context.getApplicationContext();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
int result = ContextCompat.checkSelfPermission(context, permission);
if (PackageManager.PERMISSION_DENIED == result) {
return false;
}
}
return true;
}
private static void handleRequestPermissions(T t, int requestCode, IPermission iPermission, String... permissions) {
if (t == null || permissions == null || permissions.length == 0) {
throw new IllegalArgumentException("invalidate params");
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Activity activity = getActivity(t);
List deniedPermissions = getDeniedPermissions(activity, permissions);
if (deniedPermissions != null && deniedPermissions.size() > 0) {
List rationalPermissions = new ArrayList<>();
for (String deniedPermission : deniedPermissions) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
deniedPermission)) {
rationalPermissions.add(deniedPermission);
}
}
boolean showRational = false;
if (iPermission != null) {
showRational = iPermission.showRational(requestCode);
}
if (rationalPermissions.size() > 0 && showRational) {
if (iPermission != null) {
iPermission.onRational(requestCode, deniedPermissions);
}
} else {
requestPermissions(t, requestCode, deniedPermissions);
}
} else {
if (iPermission != null) {
iPermission.onGranted(requestCode);
}
}
} else {
if (iPermission != null) {
iPermission.onGranted(requestCode);
}
}
}
@Nullable
private static Activity getActivity(T t) {
Activity activity = null;
if (t instanceof Activity) {
activity = (Activity) t;
} else if (t instanceof Fragment) {
activity = ((Fragment) t).getActivity();
} else if (t instanceof android.app.Fragment) {
activity = ((android.app.Fragment) t).getActivity();
}
return activity;
}
@TargetApi(Build.VERSION_CODES.M)
private static void requestPermissions(T t, int requestCode, List deniedPermissions) {
if (deniedPermissions == null || deniedPermissions.size() == 0) {
return;
}
// has denied permissions
if (t instanceof Activity) {
((Activity) t).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
} else if (t instanceof Fragment) {
((Fragment) t).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
} else if (t instanceof android.app.Fragment) {
((android.app.Fragment) t).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
}
}
private static List getDeniedPermissions(Context context, String... permissions) {
if (context == null || permissions == null || permissions.length == 0) {
return null;
}
List denyPermissions = new ArrayList<>();
for (String permission : permissions) {
if (!checkSelfPermission(context, permission)) {
denyPermissions.add(permission);
}
}
return denyPermissions;
}
private static void requestResult(T t, int requestCode, String[] permissions,
int[] grantResults, IPermission iPermission) {
List deniedPermissions = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permissions[i]);
}
}
if (deniedPermissions.size() > 0) {
if (iPermission != null) {
iPermission.onDenied(requestCode);
}
} else {
if (iPermission != null) {
iPermission.onGranted(requestCode);
}
}
}
}
interface IPermission {
void onGranted(int requestCode);
void onDenied(int requestCode);
void onRational(int requestCode, List permissions);
/**
* 是否需要提示用戶該權限的作用,提示後需要再調用requestPermission()方法來申請。
*
* @return true 為提示,false為不提示
*/
boolean showRational(int requestCode);
}
使用方法:
public class MainFragment extends Fragment implements View.OnClickListener {
private Button mReqCameraBt;
private Button mReqContactsBt;
private Button mReqMoreBt;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
findView(view);
initView();
return view;
}
private void findView(View view) {
mReqCameraBt = (Button) view.findViewById(R.id.bt_requestCamera);
mReqContactsBt = (Button) view.findViewById(R.id.bt_requestContacts);
mReqMoreBt = (Button) view.findViewById(R.id.bt_requestMore);
}
private void initView() {
mReqCameraBt.setOnClickListener(this);
mReqContactsBt.setOnClickListener(this);
mReqMoreBt.setOnClickListener(this);
}
public static final int REQUEST_CODE_CAMERA = 0;
public static final int REQUEST_CODE_CONTACTS = 1;
public static final int REQUEST_CODE_MORE = 2;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionUtil.onRequestPermissionsResult(this, requestCode, permissions, grantResults, mPermission);
}
public void requestCamera() {
PermissionUtil.checkPermissions(this, REQUEST_CODE_CAMERA, mPermission, Manifest.permission.CAMERA);
}
public void requestReadContacts() {
PermissionUtil.checkPermissions(this, REQUEST_CODE_CONTACTS, mPermission, Manifest.permission.READ_CONTACTS);
}
public void requestMore() {
PermissionUtil.checkPermissions(this, REQUEST_CODE_MORE, mPermission, Manifest.permission.READ_CONTACTS, Manifest.permission.READ_CALENDAR, Manifest.permission.CALL_PHONE);
}
private void showPermissionTipDialog(final int requestCode, final List permissions) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("I want you permissions");
builder.setTitle("Hello Permission");
builder.setPositiveButton("確認", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
PermissionUtil.requestPermission(MainFragment.this, requestCode, permissions);
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
public IPermission mPermission = new IPermission() {
@Override
public void onGranted(int requestCode) {
Toast.makeText(getActivity(), "onGranted :" + requestCode, Toast.LENGTH_SHORT).show();
}
@Override
public void onDenied(int requestCode) {
Toast.makeText(getActivity(), "onDenied :" + requestCode, Toast.LENGTH_SHORT).show();
}
@Override
public void onRational(int requestCode, List permission) {
showPermissionTipDialog(requestCode, permission);
}
@Override
public boolean showRational(int requestCode) {
switch (requestCode) {
case REQUEST_CODE_MORE:
return true;
default:
break;
}
return false;
}
};
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.bt_requestCamera:
requestCamera();
break;
case R.id.bt_requestContacts:
requestReadContacts();
break;
case R.id.bt_requestMore:
requestMore();
break;
}
}
}
生成的Android應用APK文件最好進行優化,因為APK包的本質是一個zip壓縮文檔,經過優化
本文實例講述了Android編程實現自定義PopupMenu樣式。分享給大家供大家參考,具體如下:PopupMenu是Android中一個十分輕量級的組件。與PopupW
資源是好不容易下載到的,關於代碼,沒什麼好說的。 說點這期間遇到的問題。 漫畫 的每一話大概有20幾個頁面,實際都是jpg圖片,
Android 斷點續傳原理以及實現0. 前言在Android開發中,斷點續傳聽起來挺容易,在下載一個文件時點擊暫停任務暫停,點擊開始會繼續下載文件。但是真正