1. 程式人生 > >Android-監聽作業系統簡訊

Android-監聽作業系統簡訊

想要訪問Android作業系統的ContentProvider就需要明白以下原理:

 

在Android作業系統裡面的 /packsges/目錄:

  apps: 很多的系統應用,例如:聯絡人,瀏覽器,音樂播放器,設定,相機 ......

                                      ............

  providers:系統對外暴露的ContentProvider:

                      

  這樣就明白了,Android作業系統裡面的應用(apps),是訪問系統對外暴露的ContentProvider(providers)

 

既然說Android作業系統裡面的應用(apps),是訪問系統對外暴露的ContentProvider(providers):

  /data/data/com.android.mms(放置在apps目錄裡面)

  /data/data/com.android.providers.telephony(放置在providers目錄裡面)

mms(簡訊應用) 是呼叫 providers.telephony(內容提供者裡面的資料),如圖:

 

 


簡訊應用沒有資料庫,那簡訊應用的資料是從哪裡來的 ?

 

答:簡訊應用是去 增刪改查了 com.android.providers.telephony 暴露簡訊資料的應用

 

apps:packages/apps/Mms   Android檔案系統裡 /data/data/com.android.mms    簡訊應用

 

 

provider: packages/provider/  Android檔案系統裡 /data/data/com.android.providers.telephony 暴露簡訊資料的應用

 


 

 

閱讀packages/provider/TelephonyProvider/com.android.providers.telephony 暴露簡訊資料的應用 資料庫:

mmssms.db 資料庫 其他應用是沒有許可權訪問的,為什麼所有應用都能獲取到 packgeas/providers/....裡面到所有應用,因為這些應用通過ContentProvider對外暴露了 

 

閱讀mmssms.db

開啟後:表非常多,等等, 但是隻需要關注一張核心的表,sms

 

關注的欄位:address:簡訊號碼,   date:簡訊時間    ,body:簡訊內容

            

 

手機裡只有一條簡訊:

 

 

閱讀packages/provider/TelephonyProvider/com.android.providers.telephony AndroidManifest.xml

 檢視AndroidManifest.xml provider節點:關注ContentProvider物件,授權,許可權 等;

SmsProvider:內容提供者

sms:授權,這授權真短

exported:對外輸出

READ_SMS/WRITE_SMS:訪問者必須要配置的許可權

     <!-- This is a singleton provider that is used by all users.
             A new instance is not created for each user. And the db is shared
             as well. -->
        <provider android:name="SmsProvider"
                  android:authorities="sms"
                  android:multiprocess="false"
                  android:exported="true"
                  android:singleUser="true"
                  android:readPermission="android.permission.READ_SMS"
                  android:writePermission="android.permission.WRITE_SMS" />

 

閱讀packages/provider/TelephonyProvider/com.android.providers.telephony SmsProvider.java

 首先要找到的就是Uri,所以搜尋UriMatcher的matcher.addURI

private static final UriMatcher sURLMatcher =
            new UriMatcher(UriMatcher.NO_MATCH);

    static {
        sURLMatcher.addURI("sms", null, SMS_ALL);
        sURLMatcher.addURI("sms", "#", SMS_ALL_ID);
        sURLMatcher.addURI("sms", "inbox", SMS_INBOX);
        sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);
        sURLMatcher.addURI("sms", "sent", SMS_SENT);
        sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);
        sURLMatcher.addURI("sms", "draft", SMS_DRAFT);
        sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);
        sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);
        sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);
        sURLMatcher.addURI("sms", "undelivered", SMS_UNDELIVERED);
        sURLMatcher.addURI("sms", "failed", SMS_FAILED);
        sURLMatcher.addURI("sms", "failed/#", SMS_FAILED_ID);
        sURLMatcher.addURI("sms", "queued", SMS_QUEUED);
        sURLMatcher.addURI("sms", "conversations", SMS_CONVERSATIONS);
        sURLMatcher.addURI("sms", "conversations/*", SMS_CONVERSATIONS_ID);
        sURLMatcher.addURI("sms", "raw", SMS_RAW_MESSAGE);
        sURLMatcher.addURI("sms", "attachments", SMS_ATTACHMENT);
        sURLMatcher.addURI("sms", "attachments/#", SMS_ATTACHMENT_ID);
        sURLMatcher.addURI("sms", "threadID", SMS_NEW_THREAD_ID);
        sURLMatcher.addURI("sms", "threadID/*", SMS_QUERY_THREAD_ID);
        sURLMatcher.addURI("sms", "status/#", SMS_STATUS_ID);
        sURLMatcher.addURI("sms", "sr_pending", SMS_STATUS_PENDING);
        sURLMatcher.addURI("sms", "icc", SMS_ALL_ICC);
        sURLMatcher.addURI("sms", "icc/#", SMS_ICC);
        //we keep these for not breaking old applications
        sURLMatcher.addURI("sms", "sim", SMS_ALL_ICC);
        sURLMatcher.addURI("sms", "sim/#", SMS_ICC);
 

 sURLMatcher.addURI("sms", null, SMS_ALL);  就是全部簡訊內容的Uir,path等於null,這樣寫是可以的,代表全部的意思

 

在這原始碼中,一定有傳送改變通知的程式碼:

搜尋:.notifyChange

系統原始碼中 而且還另外兩條通知的uri

 


 

 

測試的應用:AndroidManifest.xml 配置許可權

  <!--
        訪問作業系統簡訊內容提供者應用,需要加入的許可權
        android:readPermission="android.permission.READ_SMS"
        android:writePermission="android.permission.WRITE_SMS"
    -->
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.WRITE_SMS"/>

 

測試的應用:監聽Android作業系統聯絡人內容提供者應用裡面的簡訊資料傳送的改變

package liudeli.cp.client;

import android.app.Activity;
import android.app.AlertDialog;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;

public class SmsActivity extends Activity {

    /**
     * 定義訪問作業系統簡訊內容提供者應用的Uri
     * android:authorities="sms"
     */
    private final String AUTHORITIES = "content://sms";
    private Uri telephonyUri = Uri.parse(AUTHORITIES);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_sms);

        /**
         * 註冊內容觀察者監聽器:用於監聽/data/data/com.android.providers.telephony內容提供者應用
         * 引數一:定義訪問作業系統簡訊內容提供者應用的Uri android:authorities="sms"
         * 引數二:要聯級
         * 引數三:監聽器
         */
        getContentResolver().registerContentObserver(telephonyUri, true, contentObserver);
    }

    private ContentObserver contentObserver = new ContentObserver(new Handler()) {

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);

            // 簡訊資料傳送改變啦 ...

            /**
             * 查詢簡訊最新的一條資訊顯示
             */
            Cursor cursor = getContentResolver().query(telephonyUri,
                    new String[]{"address", "date", "body"},
                    null, // 查詢條件為null
                    null , // 查詢條件的值為null
                    " _id desc"); // 倒序,查詢出來的第一條就是最新的簡訊

            // Cursor遊標必須往下移,才能取出資料
            if (cursor.moveToFirst()) { // 移動到第一條
                String address = cursor.getString(cursor.getColumnIndex("address"));
                String body = cursor.getString(cursor.getColumnIndex("body"));
                alterUser(address, body);
            }

            // 關閉遊標
            cursor.close();
        }
    };

    private void alterUser(String address, String body) {
        new AlertDialog.Builder(this)
                .setPositiveButton("我知道了", null)
                .setTitle("注意")
                .setMessage("簡訊傳送改變啦, /n 簡訊號碼:" + address + " /n 簡訊內容:" + body)
                .show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 解除監聽器
         */
        getContentResolver().unregisterContentObserver(contentObserver);
    }
}

 


 

Android作業系統裡面的應用(apps),是訪問系統對外暴露的ContentProvider(providers)

自己開發的應用,也是可以訪問系統對外暴露的ContentProvider(providers)