由於監聽系統短信廣播受到權限的限制,所以很多手機可能使用這種方式沒法監聽廣播,從而沒辦法獲取到系統短信,所以又重新開辟一條路。
Android監聽系統短信數據庫內容變化使用場景:
1、監聽短信數據庫的變化,添加刪除修改,變化的時候會回調onChange方法
2、提取剛剛變化的那條短信的內容
備注:
1、這種方式雖然一開始能夠監聽到數據變化,但是要判斷是剛剛接手到的短信,還需要做一些處理,具體看代碼
2、這種方式需要從數據庫里面去讀取剛剛加入的那條短信,所以需要讀取數據庫權限,會彈出系統的權限申請框,所以注意使用時機
import android.content.ContentResolver; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.text.TextUtils; /** * 數據庫觀察者 */
public class SmsDatabaseChaneObserver extends ContentObserver { // 只檢查收件箱
public static final Uri MMSSMS_ALL_MESSAGE_URI = Uri.parse("content://sms/inbox"); public static final String SORT_FIELD_STRING = "_id asc"; // 排序
public static final String DB_FIELD_ID = "_id"; public static final String DB_FIELD_ADDRESS = "address"; public static final String DB_FIELD_PERSON = "person"; public static final String DB_FIELD_BODY = "body"; public static final String DB_FIELD_DATE = "date"; public static final String DB_FIELD_TYPE = "type"; public static final String DB_FIELD_THREAD_ID = "thread_id"; public static final String[] ALL_DB_FIELD_NAME = { DB_FIELD_ID, DB_FIELD_ADDRESS, DB_FIELD_PERSON, DB_FIELD_BODY, DB_FIELD_DATE, DB_FIELD_TYPE, DB_FIELD_THREAD_ID }; public static int mMessageCount = -1; private static final long DELTA_TIME = 60 * 1000; private ContentResolver mResolver; public SmsDatabaseChaneObserver(ContentResolver resolver, Handler handler) { super(handler); mResolver = resolver; } @Override public void onChange(boolean selfChange) { onReceiveSms(); } private void onReceiveSms() { Cursor cursor = null; // 添加異常捕捉
try { cursor = mResolver.query(MMSSMS_ALL_MESSAGE_URI, ALL_DB_FIELD_NAME, null, null, SORT_FIELD_STRING); final int count = cursor.getCount(); if (count <= mMessageCount) { mMessageCount = count; return; } // 發現收件箱的短信總數目比之前大就認為是剛接收到新短信---如果出現意外,請神保佑 // 同時認為id最大的那條記錄為剛剛新加入的短信的id---這個大多數是這樣的,發現不一樣的情況的時候可能也要求神保佑了
mMessageCount = count; if (cursor != null) { cursor.moveToLast(); final long smsdate = Long.parseLong(cursor.getString(cursor.getColumnIndex(DB_FIELD_DATE))); final long nowdate = System.currentTimeMillis(); // 如果當前時間和短信時間間隔超過60秒,認為這條短信無效
if (nowdate - smsdate > DELTA_TIME) { return; } final String strAddress = cursor.getString(cursor.getColumnIndex(DB_FIELD_ADDRESS)); // 短信號碼 final String strbody = cursor.getString(cursor.getColumnIndex(DB_FIELD_BODY)); // 在這里獲取短信信息 final int smsid = cursor.getInt(cursor.getColumnIndex(DB_FIELD_ID)); if (TextUtils.isEmpty(strAddress) || TextUtils.isEmpty(strbody)) { return; } // 得到短信號碼和內容之后進行相關處理
} } catch (Exception e) { e.printStackTrace(); } finally { if (cursor != null) { try { // 有可能cursor都沒有創建成功
cursor.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
下面是對數據庫觀察者的注冊,使用方式與廣播類似,生命周期也需要自己控制,結合自己使用的Activity或者Service的生命周期來進行控制。
public static final Uri SMS_MESSAGE_URI = Uri.parse("content://sms"); private static SmsDatabaseChaneObserver mSmsDBChangeObserver; private static void registerSmsDatabaseChangeObserver(ContextWrapper contextWrapper) { //因為,某些機型修改rom導致沒有getContentResolver
try { SmsDatabaseChaneObserver = new SmsDatabaseChaneObserver(contextWrapper.getContentResolver(), new Handler()); contextWrapper.getContentResolver().registerContentObserver(SMS_MESSAGE_URI, true, mSmsDBChangeObserver); } catch (Throwable b) { } } private static void unregisterSmsDatabaseChangeObserver(ContextWrapper contextWrapper) { try { contextWrapper.getContentResolver().unregisterContentObserver(SmsDatabaseChaneObserver); } catch (Exception e) { e.printStackTrace(); } }
監聽一般放在Service中,所以需要在Service時創建時注冊監聽,Service銷毀時取消監聽
