天天看點

Android項目:手機安全衛士(6)—— 手機防盜設定向導(二)Android項目:手機安全衛士(6)—— 手機防盜設定向導(二)

Android項目:手機安全衛士(6)—— 手機防盜設定向導(二)

1 介紹

前面的文章介紹了設定向導的界面與切換邏輯,今天來看看每個界面後面涉及到的代碼邏輯,主要知識點有:

  • 讀取手機 sim 卡序列号
  • 監聽手機重新開機完成的廣播
  • 讀取手機通訊錄

關于項目相關文章,請通路:

  • Android 項目:手機安全衛士(1)—— 閃屏界面
  • Android 項目:手機安全衛士(2)—— 版本更新
  • Android 項目:手機安全衛士(3)—— 主界面布局
  • Android 項目:手機安全衛士(4)—— 自定義(組合)控件、屬性
  • Android 項目:手機安全衛士(5)—— 自定義彈窗
  • Android 項目:手機安全衛士(6)—— 手機防盜設定向導

項目源碼位址(實時更新):https://github.com/xwdoor/MobileSafe

2 讀取手機 SIM 卡序列号

讀取 sim 卡序列号,然後通過 SharedPreferences 儲存,下面是代碼:

//擷取系統服務
    TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    //擷取 sim 卡序列号
    String simSerialNumber = tm.getSimSerialNumber();
           

僅僅隻是這樣,系統會報錯的:

java.lang.SecurityException: Requires READ_PHONE_STATE: Neither user 10053 nor current process has android.permission.READ_PHONE_STATE.

這是因為沒有添權重限的結果,需要添加讀取手機狀态的權限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

3 監聽手機重新開機完成的 Receiver 廣播

綁定 sim 卡後,接下來需要做的就是在手機每次啟動完成後,檢測手機 sim 卡是否發生變化,建立廣播接收器 BootCompleteReceiver,繼承自 BroadcastReceiver:

public class BootCompleteReceiver extends BroadcastReceiver {
        public BootCompleteReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            String serialNumber = PrefUtils.getString(BaseActivity.PREF_BIND_SIM,"",context);

            if(!TextUtils.isEmpty(serialNumber)){
                TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
                String simSerialNumber = tm.getSimSerialNumber();

                if(serialNumber.equals(simSerialNumber)){
                    Log.i(BaseActivity.TAG_LOG,"手機安全");
                }else {
                    Log.i(BaseActivity.TAG_LOG,"SIM卡發生變化,危險");

                }
            }
        }
    }
           

當然,這個時候還沒有添加代碼的處理邏輯,隻是輸出日志。注意,接收該廣播還需要添權重限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

建立完成後,需要注冊該廣播接收器,且它的 action 是:BOOT_COMPLETED,代碼如下:

<receiver
        android:name=".receiver.BootCompleteReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
        </intent-filter>
    </receiver>
           

4 讀取手機通訊錄

通過通路系統的 ContentProvider 來讀取通訊錄,系統有三張表,分别是 raw_contacts, data, mimetypes,我們的大概思路是:

  1. 讀取 raw_contacts, 擷取 contact_id
  2. 根據 contact_id, 從 data 中讀取具體資訊(姓名/電話 ) data1, mimetype_id
  3. 根據 mimetype_id, 從 mimetypes 中查到具體類型
/**
     * 讀取聯系人
     */
    private ArrayList<HashMap<String, String>> readContacts() {
        // raw_contacts, data, mimetypes
        // 1. 讀取raw_contacts, 擷取contact_id
        // 2. 根據contact_id, 從data中讀取具體資訊(姓名/電話 ) data1, mimetype_id
        // 3. 根據mimetype_id, 從mimetypes中查到具體類型

        // 1. 讀取raw_contacts, 擷取contact_id
        Cursor rawCursor = getContentResolver().query(Uri.parse("content://com.android.contacts/raw_contacts"),
                new String[]{"contact_id"}, null, null, null);

        ArrayList<HashMap<String, String>> listContacts = new ArrayList<>();
        if (rawCursor != null) {
            while (rawCursor.moveToNext()) {
                String contactId = rawCursor.getString(rawCursor.getColumnIndex("contact_id"));

                // 2. 根據contact_id, 從data中讀取具體資訊(姓名/電話 ) data1, mimetype_id
                // 系統在查詢data表時, 實際上查詢的時view_data這個視圖, 視圖将data和mimetypes兩個表的資訊整合在了一起
                Cursor cursor = getContentResolver().query(Uri.parse("content://com.android.contacts/data"),
                        new String[]{"data1", "mimetype"}, "raw_contact_id=?", new String[]{contactId}, null);

                HashMap<String, String> map = new HashMap<>();
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        String data = cursor.getString(cursor.getColumnIndex("data1"));
                        String mimetype = cursor.getString(cursor.getColumnIndex("mimetype"));

                        if ("vnd.android.cursor.item/name".equals(mimetype)) {
                            //姓名
                            map.put("name", data);
                        } else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                            //電話
                            map.put("phone", data);
                        }
                    }
                    cursor.close();

                    if (!TextUtils.isEmpty(map.get("name")) && !TextUtils.isEmpty(map.get("phone"))) {// 過濾掉髒資料
                        listContacts.add(map);
                    }
                }

            }
            rawCursor.close();
        }
        return listContacts;
    }
           

僅僅隻是這樣,系統會報錯的:

java.lang.SecurityException: Permission Denial: reading com.android.providers.contacts.ContactsProvider2 requires android.permission.READ_CONTACTS, or grantUriPermission().

需要添權重限:

<uses-permission android:name="android.permission.READ_CONTACTS"/>

5 總結

我覺得今天的知識點很有用,使用了系統提供的一些服務,這些服務一般都需要通路權限,是以不要忘了權重限,我也是忘了好幾次,謹記。

關于項目相關文章,請通路:

  • Android 項目:手機安全衛士(1)—— 閃屏界面
  • Android 項目:手機安全衛士(2)—— 版本更新
  • Android 項目:手機安全衛士(3)—— 主界面布局
  • Android 項目:手機安全衛士(4)—— 自定義(組合)控件、屬性
  • Android 項目:手機安全衛士(5)—— 自定義彈窗
  • Android 項目:手機安全衛士(6)—— 手機防盜設定向導

項目源碼位址(實時更新):https://github.com/xwdoor/MobileSafe