一、目標
在Html5代碼已經移植至Android工程後,完成Android App開發的基本框架之權限設置部分的代碼設計與開發;
二、步驟
1、在AndroidManifest.xml中定義需要使用到的權限,如本項目中使用的權限如下:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
2、配置以後,需要在代碼中去檢查是否有權限,核心代碼如下:
int resultPermission = ContextCompat.checkSelfPermission(activity, permission);
該返回值爲PackageManager.PERMISSION_GRANTED時,表示已經授權,否則需要下一步去申請權限;
3、申請權限核心代碼:
ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
注意:shouldShowRequestPermissionRationale爲異步方法,負責調取一個申請授權的彈窗,如果同時申請多個這種權限的彈窗,則只彈出第一個,後面的彈窗直接跳過。
4、獲取授權結果,需要基於請求權限的請求碼,在MainActivity中的onRequestPermissionsResult回調方法中去處理;
5、上面基於第3步,由於多次彈窗被跳過了,則需要調用第3步的申請權限方法,繼續申請下一個權限項,直到所有權限申請完畢;
6、基於上述邏輯,彙總下核心代碼邏輯(完整代碼見github):
MainActivity中與權限相關的代碼:
package com.justinsoft.activity;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.justinsoft.R;
import com.justinsoft.constant.Constant;
import com.justinsoft.permission.PermissionMgr;
import com.justinsoft.util.LogUtil;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
// 日誌句柄
private static final String TAG = LogUtil.getClassTag(MainActivity.class);
private BtWebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1.打開權限設置
loadPermission(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
Log.i(TAG, "update permission now.");
PermissionMgr permissionMgr = PermissionMgr.getInstance();
permissionMgr.updatePermission(this, requestCode, permissions, grantResults);
if (permissionMgr.hasRequestAllPermission()) {
refreshHomepage();
}
}
/**
* 檢查並請求打開權限設置
*
* @param activity
*/
private void loadPermission(Activity activity) {
Map<Integer, Set<String>> allPermission = new HashMap<Integer, Set<String>>();
Set<String> locationPermission = new HashSet<String>();
locationPermission.add(Manifest.permission.ACCESS_FINE_LOCATION);
locationPermission.add(Manifest.permission.ACCESS_COARSE_LOCATION);
allPermission.put(Constant.LOCATION_PERMISSION_CODE, locationPermission);
Set<String> audioPermission = new HashSet<String>();
audioPermission.add(Manifest.permission.RECORD_AUDIO);
allPermission.put(Constant.RECORD_PERMISSION_CODE, audioPermission);
Set<String> cameraPermission = new HashSet<String>();
cameraPermission.add(Manifest.permission.CAMERA);
allPermission.put(Constant.CAMERA_PERMISSION_CODE, cameraPermission);
Set<String> storagePermission = new HashSet<String>();
storagePermission.add(Manifest.permission.READ_EXTERNAL_STORAGE);
storagePermission.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
allPermission.put(Constant.STORAGE_PERMISSION_CODE, storagePermission);
PermissionMgr.getInstance().requestPermission(activity, allPermission);
}
}
抽取的權限管理類PermissionMgr:
package com.justinsoft.permission;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.justinsoft.util.LogUtil;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.LocationManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
public final class PermissionMgr
{
// 日誌標記
private static final String TAG = LogUtil.getClassTag(PermissionMgr.class);
// 權限管理
private static PermissionMgr permissionMgr;
private static final Lock LOCK = new ReentrantLock();
private Set<Integer> requestedPermissionCode;
private Set<Integer> grantPermissionCode;
private Map<Integer, Set<String>> allPermission;
private PermissionMgr()
{
requestedPermissionCode = new HashSet<Integer>();
grantPermissionCode = new HashSet<Integer>();
}
public static PermissionMgr getInstance()
{
if (null == permissionMgr)
{
LOCK.tryLock();
try
{
if (null == permissionMgr)
{
permissionMgr = new PermissionMgr();
}
return permissionMgr;
}
catch (Exception e)
{
Log.e(TAG, "failed to get permission", e);
}
finally
{
LOCK.unlock();
}
}
return permissionMgr;
}
/**
* 請求權限
*
* @param activity
* @param allPermission
*/
public void requestPermission(Activity activity, Map<Integer, Set<String>> allPermission)
{
this.allPermission = allPermission;
requestLeftPermission(activity, allPermission);
}
/**
* 判斷權限請求結束後,是否獲取到權限
*
* @param activity
* @param requestCode
* @param permissions
* @param grantResults
* @return
*/
public void updatePermission(Activity activity, int requestCode, String permissions[], int[] grantResults)
{
Log.i(TAG, "request permission code:" + requestCode);
Log.i(TAG, "all permission code:" + allPermission.keySet());
Log.i(TAG, "all permission:" + permissions);
if (!allPermission.keySet().contains(requestCode))
{
Log.i(TAG, "invalid permission");
return;
}
requestedPermissionCode.add(requestCode);
// 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.
Log.i(TAG, "grant permission now:" + requestCode);
grantPermissionCode.add(requestCode);
}
else
{
// permission denied, boo! Disable the
// functionality that depends on this permission.
Log.i(TAG, "no permission now:" + requestCode);
}
Map<Integer, Set<String>> ungrantPermission = new HashMap<Integer, Set<String>>();
ungrantPermission.putAll(allPermission);
ungrantPermission.keySet().removeAll(requestedPermissionCode);
Log.i(TAG, "Left permission:" + ungrantPermission.keySet());
requestLeftPermission(activity, ungrantPermission);
}
/**
* 是否已經申請了足夠的權限
*
* @return
*/
public boolean hasRequestAllPermission()
{
Map<Integer, Set<String>> ungrantPermission = new HashMap<Integer, Set<String>>();
ungrantPermission.putAll(allPermission);
ungrantPermission.keySet().removeAll(requestedPermissionCode);
return ungrantPermission.isEmpty();
}
/**
* 請求剩餘權限
*
* @param activity
* @param allPermission
*/
private void requestLeftPermission(Activity activity, Map<Integer, Set<String>> allPermission)
{
for (Map.Entry<Integer, Set<String>> entry : allPermission.entrySet())
{
int grantPermission = -1;
boolean isLocationPermission = false;
int requestCode = entry.getKey();
Set<String> batchPermission = entry.getValue();
for (String permission : batchPermission)
{
int resultPermission = ContextCompat.checkSelfPermission(activity, permission);
if (resultPermission == PackageManager.PERMISSION_GRANTED)
{
this.requestedPermissionCode.add(requestCode);
grantPermission = PackageManager.PERMISSION_GRANTED;
}
if (permission.equalsIgnoreCase(Manifest.permission.ACCESS_FINE_LOCATION)
|| permission.equalsIgnoreCase(Manifest.permission.ACCESS_COARSE_LOCATION))
{
isLocationPermission = true;
}
}
if (grantPermission != PackageManager.PERMISSION_GRANTED)
{
boolean result = shouldPermission(activity, batchPermission);
if (isLocationPermission)
{
List<String> allProvider = getLocationProvider(activity);
if (null == allProvider || allProvider.isEmpty())
{
result = false;
}
}
if (!result)
{
Log.i(TAG, "It needs to request permission now.");
ActivityCompat.requestPermissions(activity, batchPermission.toArray(new String[] {}), requestCode);
}
return;
}
}
}
private boolean shouldPermission(Activity activity, Set<String> batchPermission)
{
for (String permission : batchPermission)
{
if (!this.requestedPermissionCode.contains(permission))
{
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission))
{
Log.i(TAG, "grant permission:" + permission);
return true;
}
}
}
return false;
}
private List<String> getLocationProvider(Activity activity)
{
LocationManager locationManager = (LocationManager)activity.getSystemService(Activity.LOCATION_SERVICE);
Criteria criteria = new Criteria();
List<String> allProviderName = locationManager.getProviders(criteria, true);
Log.i(TAG, "provider:" + allProviderName);
return allProviderName;
}
}
三、總結
權限申請是Android開發的基本訴求之一,在開發過程中,先是一股腦全申請了彈窗,結果發現只彈了一次就不彈了,後面就想到在Activity中的回調方法onRequestPermissionsResult中繼續申請下一個權限,終於達成一個接一個彈窗的目標;
四、參考資料
[1]https://www.cnblogs.com/Free-Thinker/p/6014765.html
上一篇:Vue.js實戰——移植Html5 App爲Android App_10