上篇文章中提到噪舀,安全測試的一個需求是每次由后臺切換到前臺的時候都要走一遍登錄界面,登錄界面就是我的啟動頁甥桂,講的是只要在配置文件中設置啟動頁activity的啟動模式為singleTask就可以了,之后好像對這個效果不滿意(是我解決的太快,感覺太簡單了么津坑??)傲霸,所以給出了另外一種方案疆瑰。
每次進到后臺,從后臺切換到前臺的時候昙啄,只要不是在登錄界面穆役,就給彈一個dialog,提示用戶輸入密碼驗證身份梳凛,驗證成功進入耿币,點擊取消的話進入到登錄界面重新登錄。
1韧拒、首先要解決的問題就是判斷程序在前臺還是在后臺淹接。
因為要監(jiān)聽所有的activity狀態(tài),所以判斷應該寫在BaseActivity中
/**
* 應用是否在前臺運行
*
* @return true:在前臺運行叛溢;false:已經被切到后臺了
*/
private boolean isAppOnForeground() {
ActivityManager mActivityManager = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
? ? List appProcesses = mActivityManager.getRunningAppProcesses();
? ? if (appProcesses !=null) {
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
if (appProcess.processName.equals("cn.bzzy.com.bzzy_app")) {
//以下兩句話是保存是否在后臺的布爾值塑悼,判斷是否顯示dialog會用到
//editor.putBoolean("comefromback", false);
? ? ? ? ? ? ? ? ? //editor.apply();
return true;
? ? ? ? ? ? ? ? }
}
}
}
Toast.makeText(getApplicationContext(), "注意,標準作業(yè)已進入后臺運行", Toast.LENGTH_SHORT).show();
? ? //editor.putBoolean("comefromback", true);
? ? //editor.apply();
return false;
}
值得注意的是楷掉,這個方法應該寫在哪里厢蒜,一開始我是寫在onPause()方法里面的,發(fā)現怎么都不可以靖诗,后來換到onStop()方法中就可以了郭怪。
想想為什么要在onStop中檢測,而不是onPause刊橘?這是由于A啟動B時鄙才,生命周期的執(zhí)行順序如下:A.onPause->B.onCreate->B.onStart->B.onResume->A.onStop,也就是說促绵,在A的onPause方法中攒庵,B的生命周期還沒有執(zhí)行,進程沒有進入前臺败晴,當然是檢測不到的浓冒。
好了第一步已經完成了,接下來第二步尖坤。
2稳懒、第二步是顯示dialog。
private AlertDialog passwordDialog ;
private void showDialog() {
final EditText editText =new EditText(BaseActivity.this);
? ? ? ? passwordDialog =
new AlertDialog.Builder(BaseActivity.this).
setTitle("請重新輸入密碼驗證身份").setView(editText)
.setPositiveButton("確定", null)
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
? ? ? ? ? ? ? ? ? ? ? ? ? ? public void onClick(DialogInterface dialog, int which) {
Intent intent =new Intent(getApplicationContext(), LoginActivity.class);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? startActivity(intent);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? finish();
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
}).setCancelable(false).create();
//? ? ? ? if(passwordDialog!=null && !passwordDialog.isShowing()){
? ? ? ? ? ? passwordDialog.show();
//? ? ? ? }
? ? ? ? passwordDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
? ? ? ? ? ? public void onClick(View v) {
final String password =editText.getText().toString().trim();
? ? ? ? ? ? ? ? if (!password.equals("")) {
if (!CipherUtils.sm2DecryptHex(passwordPref.getString("password", "")).equals(password)) {
ToastUtil.showShort(getApplicationContext(), "密碼錯誤");
? ? ? ? ? ? ? ? ? ? }else {
ToastUtil.showShort(getApplicationContext(), "驗證成功");
? ? ? ? ? ? ? ? ? ? ? ? passwordDialog.dismiss();
? ? ? ? ? ? ? ? ? ? }
}else {
ToastUtil.showShort(getApplicationContext(), "請輸入密碼");急
? ? ? ? ? ? ? ? }
}
});
? ? }
一開始在實現的時候以為就是簡單的show出來一個dialog慢味,后來發(fā)現默認的dialog是在點擊確定的時候自己就消失了场梆,這可不符合我們的需求啊墅冷,想想,就算你驗證了密碼不符合或油,給出toast出來說驗證不通過寞忿,但是你的dialog消失了,用戶照樣可以使用顶岸。
所以要解決這個問題腔彰,方法就是,在setPositiveButton的點擊事件中先設置為null辖佣,dialog.show()出來霹抛,然后獲取PositiveButton的點擊,通過驗證之后才讓dialog消失凌简。
還有一點就是上炎,只有在驗證成功的條件下dialog才會消失,所以要設置點擊屏幕空白部分和返回鍵dialog都不能消失雏搂,使用.setCancelable(false)藕施。
另外setCanceledOnTouchOutside(false)的作用是點擊屏幕空白部分不消失,點擊返回鍵消失凸郑。
3裳食、完成以上兩個步驟我以為完成了需求,但之后在測試的時候發(fā)現芙沥,從后臺切換到前臺的時候诲祸,顯示dialog沒錯,這時候再退回到后臺而昨,之后進入前臺發(fā)現又彈出一個dialog救氯,你會發(fā)現你在填寫密碼驗證成功之后還有一個沒有填寫東西的dialog。
解決思路:肯定要在showDialog()方法執(zhí)行之前進行判斷歌憨。
怎么判斷着憨,想到showDialog的時候實例化dialog的對象,所以在沒執(zhí)行showDialog方法之前肯定是空的
if (passwordDialog ==null){
showDialog();
}
這樣彈出一個dialog之后务嫡,對象就不為空漠另,就不會執(zhí)行showDialog方法控汉,確實也是這樣朱转,不過經過測試發(fā)現谦炒,第一次可以達到效果,之后從后臺到前臺的時候就不會有dialog彈出去扣,看看代碼柱衔,想一下,是啊,執(zhí)行過一次之后對象就不為空了啊秀存,以后也不會執(zhí)行就不會顯示dialog了捶码,要想一個辦法讓它進入到if里面執(zhí)行showDialog羽氮,后來想到dialog.isShowing()這個方法或链,如果它沒在顯示的話就讓他執(zhí)行,進入到if了档押,沒毛病澳盐,試試看
if (passwordDialog ==null || !passwordDialog.isShowing()) {
showDialog();
}
可以了,到這里目的就達到了令宿。
PS. 本人寫在這里的文章是記錄自己解決問題的過程叼耙,以便日后查看,可能會有些啰嗦粒没,也沒有排版筛婉,之前也沒有寫過。如果有幸被你看到引起不適癞松,勿噴爽撒。
以上。