1. 程式人生 > >為安卓應用新增手勢密碼功能,遇到的一些問題以及解決方法

為安卓應用新增手勢密碼功能,遇到的一些問題以及解決方法

公司的APP有個需求為他新增類似於支付寶的手勢密碼驗證功能效果圖如下
這裡寫圖片描述
首先我們要分析三個問題:
1.手勢密碼的作用是什麼?
2.在什麼時候啟動?
3.啟動之後幹什麼?

1.手勢密碼的作用是什麼?
這裡很容易解答,為了APP二次啟動進入進行驗證是否正常授權的使用者。
2.在什麼時候啟動?
如果是對安全性比較高的應用這裡推薦應用處於後臺執行狀態下馬上進入安全驗證狀態(也就是需要輸入手勢密碼才能回到之前的Activity
另一種安全效能要求是不那麼高的使用者在鎖屏之後再次回到應用啟動驗證即可。
3.啟動之後幹什麼?
手勢驗證成功就進入開啟APP,驗證失敗就不讓動~
關於手勢驗證程式碼網上一大堆,我這裡主要講解如何整合到我們的app中,畢竟在app開發中會用就行:orz

首先我們要獲取APP的狀態是否進入後臺等,這裡有幾種思路:
1.監聽HOME鍵power鍵跟返回鍵操作
2.監聽鎖屏解鎖廣播
3.自定義廣播實現監聽
由於軟體需求的安全性不高,我選擇了第二種:監聽解鎖廣播
android.intent.action.USER_PRESENT 使用者操作進行解鎖時會觸發
我們首先編寫一個CustomReceiver程式碼如下

public class CustomReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if
(intent.getAction().equals("android.intent.action.USER_PRESENT") && SPUtils.getGestureCode(context) == HAS_GESTURE) { Logger.e("存在鎖屏密碼"); SPUtils.put(context, "isLock", true); Intent intent1 = new Intent(context, SignUserGestureActivity.class); intent1.setFlags(FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); } else
{ Logger.e("不存在鎖屏密碼" + SPUtils.getGestureCode(context)); SPUtils.put(context, "isLock", false); } }

然後在清單檔案申明

 <receiver android:name=".broadcast.CustomReceiver">
    <intent-filter>
        <action android:name="android.intent.action.USER_PRESENT"/>
    </intent-filter>
</receiver>

監聽廣播並且判斷當前手勢密碼是否存在,存在跳轉到驗證Activity。注意這裡的setFlags在廣播中啟動activity必須設定flag為FLAG_ACTIVITY_NEW_TASK
否則報錯如下

Caused by: android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

鎖屏後啟動驗證解決了。現在的問題,啟動後幹什麼?兩種情況
1.APP未啟動過,處於非執行狀態,跳轉至啟動動畫即可
2.執行時,恢復到原來的Activity
第一種情況直接啟動Intent的跳轉就好了
第二種情況怎麼記錄處於棧頂的Activity?
我這裡提供一個辦法在每個activity的onResume方法中添加當前的Activity

    //全域性靜態集合保留所有的activity
    public static List<Activity> activitys=new ArrayList<>();

當手勢密碼驗證通過取得最後一個activity的名字去啟動,程式碼如下

//程式處於執行狀態只要取出最後一個執行的activity就好了
            if(activitys.size()!=0){
                lastactivityname = activitys.get(activitys.size()-1).getComponentName();
                Logger.e(activitys.size()+"");
                Intent intent = new Intent();
                intent.setComponent(lastactivityname);
                intent.setFlags(FLAG_ACTIVITY_CLEAR_TOP);//清除當前activity,讓之前啟動的Activity處於棧頂
                startActivity(intent);
            }else {
                //程式此時沒有執行啟動歡迎頁面即可
                Intent intent = new Intent(this,ShowFirstActivity.class);
                startActivity(intent);

            }

注意這裡的FLAG_ACTIVITY_CLEAR_TOP

這裡貼上Intent 的常見Flag

先首先簡單介紹下Task和Activity的關係

Task就像一個容器,而Activity就相當與填充這個容器的東西,第一個東西(Activity)則會處於最下面,最後新增的東西(Activity)則會在最上面。從Task中取出東西(Activity)是從最頂端取出,也就是說最先取出的是最後新增的東西(Activity),以此類推,最後取出的是第一次新增的Activity,而Activity在Task中的順序是可以控制的,在Activity跳轉時用到Intent Flag可以設定新建activity的建立方式;

FLAG_ACTIVITY_NEW_TASK

預設的跳轉型別,它會重新建立一個新的Activity,不過與這種情況,比如說Task1中有A,B,C三個Activity,此時在C中啟動D的話,如果在AndroidManifest.xml檔案中給D添加了Affinity的值和Task中的不一樣的話,則會在新標記的Affinity所存在的Task中壓入這個Activity。如果是預設的或者指定的Affinity和Task一樣的話,就和標準模式一樣了啟動一個新的Activity.

FLAG_ACTIVITY_SINGLE_TOP

這個FLAG就相當於載入模式中的singletop,比如說原來棧中情況是A,B,C,D在D中啟動D,棧中的情況還是A,B,C,D

FLAG_ACTIVITY_CLEAR_TOP

這個FLAG就相當於載入模式中的SingleTask,這種FLAG啟動的Activity會把要啟動的Activity之上的Activity全部彈出棧空間。類如:原來棧中的情況是A,B,C,D這個時候從D中跳轉到B,這個時候棧中的情況就是A,B了

FLAG_ACTIVITY_BROUGHT_TO_FRONT

這個網上很多人是這樣寫的。如果activity在task存在,拿到最頂端,不會啟動新的Activity。這個有可能會誤導大家! 他這個FLAG其實是這個意思!比如說我現在有A,在A中啟動B,此時在A中Intent中加上這個標記。此時B就是以FLAG_ACTIVITY_BROUGHT_TO_FRONT方式啟動,此時在B中再啟動C,D(正常啟動C,D),如果這個時候在D中再啟動B,這個時候最後的棧的情況是 A,C,D,B。如果在A,B,C,D正常啟動的話,不管B有沒有用FLAG_ACTIVITY_BROUGHT_TO_FRONT啟動,此時在D中啟動B的話,還是會變成A,C,D,B的。

FLAG_ACTIVITY_NO_USER_ACTION

onUserLeaveHint()作為activity週期的一部分,它在activity因為使用者要跳轉到別的activity而要退到background時使用。比如,在使用者按下Home鍵,它將被呼叫。比如有電話進來(不屬於使用者的選擇),它就不會被呼叫。
那麼系統如何區分讓當前activity退到background時使用是使用者的選擇?

它是根據促使當前activity退到background的那個新啟動的Activity的Intent裡是否有FLAG_ACTIVITY_NO_USER_ACTION來確定的。

注意:呼叫finish()使該activity銷燬時不會呼叫該函式

FLAG_ACTIVITY_NO_HISTORY

意思就是說用這個FLAG啟動的Activity,一旦退出,它不會存在於棧中,比方說!原來是A,B,C這個時候再C中以這個FLAG啟動D的,D再啟動E,這個時候棧中情況為A,B,C,E。

至此為應用新增手勢密碼功能的邏輯就完成了。歡迎留言更好的方法。