編輯:關於Android編程
MeloDev的這篇文章跟我的想法不謀而合,不一樣的地方是在於我加了個必要權限判斷,開發中我們會發現,有些權限是必須獲取到的,不然會影響到一部分的功能,如SD卡權限,當然,如果用戶不允許開通此類權限,APP理論上來說還是要允許用戶繼續使用的,但是我們要在很多地方加入權限判斷,很是麻煩,所以干脆流氓一點吧,添加一個必要權限判斷,如果必要權限被拒絕了,先彈窗,告知用戶去個人中心手動開啟,如果不然,直接退出APP....
我將運行時權限封裝到 BaseActivity 中,BaseActivity 繼承AppCompatActivity。
注解都寫得很詳細了,直接上代碼。
回調接口:
/**
* Created by caihan on 2017/1/1.
* 權限申請接口
*/
public interface PermissionsResultListener {
void onPermissionGranted();
void onPermissionDenied();
}
BaseActivity裡的權限代碼:
/**
* Created by caihan on 2017/1/1.
*/
public abstract class BaseActivity extends AppCompatActivity{
private static final String TAG = "BaseActivity";
protected Context mContext;
// For Android 6.0
private PermissionsResultListener mListener;
//申請標記值
public static final int REQUEST_CODE_ASK_PERMISSIONS = 100;
//手動開啟權限requestCode
public static final int SETTINGS_REQUEST_CODE = 200;
//拒絕權限後是否關閉界面或APP
private boolean mNeedFinish = false;
//界面傳遞過來的權限列表,用於二次申請
private ArrayList mPermissionsList = new ArrayList<>();
//必要全選,如果這幾個權限沒通過的話,就無法使用APP
protected static final ArrayList FORCE_REQUIRE_PERMISSIONS = new ArrayList() {
{
add(Manifest.permission.INTERNET);
add(Manifest.permission.READ_EXTERNAL_STORAGE);
add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
add(Manifest.permission.ACCESS_FINE_LOCATION);
add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
};
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null) {
setIntent(intent);
mContext = this;
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//沒actionbar
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
//取消橫屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//輸入法彈出的時候不頂起布局
//如果我們不設置"adjust..."的屬性,對於沒有滾動控件的布局來說,采用的是adjustPan方式,
// 而對於有滾動控件的布局,則是采用的adjustResize方式。
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
// getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |
// WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
mContext = this;
}
/**
* 權限允許或拒絕對話框
*
* @param permissions 需要申請的權限
* @param needFinish 如果必須的權限沒有允許的話,是否需要finish當前 Activity
* @param callback 回調對象
*/
protected void requestPermission(final ArrayList permissions, final boolean needFinish,
final PermissionsResultListener callback) {
if (permissions == null || permissions.size() == 0) {
return;
}
mNeedFinish = needFinish;
mListener = callback;
mPermissionsList = permissions;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//獲取未通過的權限列表
ArrayList newPermissions = checkEachSelfPermission(permissions);
if (newPermissions.size() > 0) {// 是否有未通過的權限
requestEachPermissions(newPermissions.toArray(new String[newPermissions.size()]));
} else {// 權限已經都申請通過了
if (mListener != null) {
mListener.onPermissionGranted();
}
}
} else {
if (mListener != null) {
mListener.onPermissionGranted();
}
}
}
/**
* 申請權限前判斷是否需要聲明
*
* @param permissions
*/
private void requestEachPermissions(String[] permissions) {
if (shouldShowRequestPermissionRationale(permissions)) {// 需要再次聲明
showRationaleDialog(permissions);
} else {
ActivityCompat.requestPermissions(BaseActivity.this, permissions,
REQUEST_CODE_ASK_PERMISSIONS);
}
}
/**
* 彈出聲明的 Dialog
*
* @param permissions
*/
private void showRationaleDialog(final String[] permissions) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示")
.setMessage("為了應用可以正常使用,請您點擊確認申請權限。")
.setPositiveButton("確認",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(BaseActivity.this, permissions,
REQUEST_CODE_ASK_PERMISSIONS);
}
})
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (mNeedFinish) finish();
}
})
.setCancelable(false)
.show();
}
/**
* 檢察每個權限是否申請
*
* @param permissions
* @return newPermissions.size > 0 表示有權限需要申請
*/
private ArrayList checkEachSelfPermission(ArrayList permissions) {
ArrayList newPermissions = new ArrayList();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
newPermissions.add(permission);
}
}
return newPermissions;
}
/**
* 再次申請權限時,是否需要聲明
*
* @param permissions
* @return
*/
private boolean shouldShowRequestPermissionRationale(String[] permissions) {
for (String permission : permissions) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
return true;
}
}
return false;
}
/**
* 申請權限結果的回調
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_ASK_PERMISSIONS && permissions != null) {
// 獲取被拒絕的權限列表
ArrayList deniedPermissions = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permission);
}
}
// 判斷被拒絕的權限中是否有包含必須具備的權限
ArrayList forceRequirePermissionsDenied =
checkForceRequirePermissionDenied(FORCE_REQUIRE_PERMISSIONS, deniedPermissions);
if (forceRequirePermissionsDenied != null && forceRequirePermissionsDenied.size() > 0) {
// 必備的權限被拒絕,
if (mNeedFinish) {
showPermissionSettingDialog();
} else {
if (mListener != null) {
mListener.onPermissionDenied();
}
}
} else {
// 不存在必備的權限被拒絕,可以進首頁
if (mListener != null) {
mListener.onPermissionGranted();
}
}
}
}
/**
* 檢查回調結果
*
* @param grantResults
* @return
*/
private boolean checkEachPermissionsGranted(int[] grantResults) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private ArrayList checkForceRequirePermissionDenied(
ArrayList forceRequirePermissions, ArrayList deniedPermissions) {
ArrayList forceRequirePermissionsDenied = new ArrayList<>();
if (forceRequirePermissions != null && forceRequirePermissions.size() > 0
&& deniedPermissions != null && deniedPermissions.size() > 0) {
for (String forceRequire : forceRequirePermissions) {
if (deniedPermissions.contains(forceRequire)) {
forceRequirePermissionsDenied.add(forceRequire);
}
}
}
return forceRequirePermissionsDenied;
}
/**
* 手動開啟權限彈窗
*/
private void showPermissionSettingDialog() {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示")
.setMessage("必要的權限被拒絕")
.setPositiveButton("去設置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
AppUtils.getAppDetailsSettings(BaseActivity.this, SETTINGS_REQUEST_CODE);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
if (mNeedFinish) AppUtils.restart(BaseActivity.this);
}
})
.setCancelable(false)
.show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//如果需要跳轉系統設置頁後返回自動再次檢查和執行業務 如果不需要則不需要重寫onActivityResult
if (requestCode == SETTINGS_REQUEST_CODE) {
requestPermission(mPermissionsList, mNeedFinish, mListener);
}
}
}
跳轉應用設置和關閉APP進程的代碼:
/**
* 獲取App具體設置
*
* @param context 上下文
*/
public static void getAppDetailsSettings(Context context, int requestCode) {
getAppDetailsSettings(context, context.getPackageName(), requestCode);
}
/**
* 獲取App具體設置
*
* @param context 上下文
* @param packageName 包名
*/
public static void getAppDetailsSettings(Context context, String packageName, int requestCode) {
if (StringUtils.isSpace(packageName)) return;
((AppCompatActivity) context).startActivityForResult(
IntentUtils.getAppDetailsSettingsIntent(packageName), requestCode);
}
/**
* 獲取App具體設置的意圖
*
* @param packageName 包名
* @return intent
*/
public static Intent getAppDetailsSettingsIntent(String packageName) {
Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.parse("package:" + packageName));
return intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
/**
* 通過任務管理器殺死進程
* 需添加權限 {@code }
*
* @param context
*/
public static void restart(Context context) {
int currentVersion = android.os.Build.VERSION.SDK_INT;
if (currentVersion > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startMain);
System.exit(0);
} else {// android2.1
ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
am.restartPackage(context.getPackageName());
}
}
界面上調用代碼:
這裡我直接傳了必要權限數列過去,因此如果有任何一個權限沒通過,都會退出APP,
如果你打算分場合請求權限的話,可以修改下我的代碼,必要和非必要權限都從界面傳遞過來就可以了。
requestPermission(FORCE_REQUIRE_PERMISSIONS, true, new PermissionsResultListener() {
@Override
public void onPermissionGranted() {
ToastUtils.showShortToast("已申請權限");
}
@Override
public void onPermissionDenied() {
ToastUtils.showShortToast("拒絕申請權限");
}
});
android實現支付寶咻一咻的幾種思路方法
支付寶咻一咻在過年的時候很火熱。那麼咻一咻具體有哪些實現方式呢?下面我們將一一介紹這幾種思路的實現過程。1.自定義View實現咻一咻那麼這種實現方法需要掌握Canvas以
android的屬性動畫
前言屬性動畫(Property Animation)系統是一個更加強大的框架,它幾乎允許你為任何東西設置動畫。不管一個對象是否需要繪制到屏幕上面,你都可以定義一個動畫讓這
Android事件分發機制-------View
當觸摸一個View時,首先會調用View的dispatchTouchEvent(MotionEvent event)方法,關乎著事件的分發,所以首先看看這個方法publi
android:強大的圖片下載和緩存庫Picasso
1.Picasso簡介Picasso是Square公司出品的一個強大的圖片下載和緩存圖片庫。官方網址是:http://square.github.io/picasso/只