Android短信監聽實現,及Android4.4之後短信機制變更 Android短信監聽實現,及Android4.4之後短信機制變更

Android短信監聽實現,及Android4.4之後短信機制變更

 

前陣子公司有一個項目,簡單的監聽短信應用,功能只有如下兩個:

1.監聽短信並獲取短信內容上傳服務器;
2.從服務器獲取短信內容,發送出去
   按照傳統的思路,監聽短信我們有兩種方式;第一種是使用廣播方式監聽短信廣播到來,第二種則是通過觀察者,監聽數據庫數據變化。
    其中,指的注意的是Android4.4之後版本,新引入了默認短信應用的概念,系統可以設置由某個應用來處理短信;
本文我們將帶人們分析以下幾個問題:
   1.監聽數據庫變化方式監聽短信
   2.通過廣播監聽短信內容
   3.Android 4.4以上版本短信權限問題
   4.Android4.4版本以上設置默認短信應用
 
 

1.監聽數據庫變化方式監聽短信內容

既然是監聽數據庫變化 那我們就應該清楚短信的數據庫表結構:
sms主要結構:
  _id:          短信序號,如100
  thread_id:對話的序號,如100,與同一個手機號互發的短信,其序號是相同的
  address:  發件人地址,即手機號,如+86138138000
  person:   發件人,如果發件人在通訊錄中則爲具體姓名,陌生人爲null
  date:       日期,long型,如1346988516,可以對日期顯示格式進行設置
  protocol: 協議0SMS_RPOTO短信,1MMS_PROTO彩信
  read:      是否閱讀0未讀,1已讀
  status:    短信狀態-1接收,0complete,64pending,128failed
  type:       短信類型1是接收到的,2是已發出
  body:      短信具體內容
  service_center:短信服務中心號碼編號,如+8613800755500 
 
既然需要操作數據庫,便少不了使用ContentResolver,所以我們應該還需要了解,短信的content uri :
全部短信:content://sms/
收件箱:content://sms/inbox
發件箱:content://sms/sent
草稿箱:content://sms/draft
 
複製代碼
private Uri SMS_INBOX = Uri.parse("content://sms/inbox");  
    public void getSmsFromPhone() {  
        ContentResolver cr = getContentResolver();  
        String[] projection = new String[] { "body","address" };//"_id", "address", "person",, "date", "type  
        String where = " date >  "  
                + (System.currentTimeMillis() - 10 * 60 * 1000);  
        Cursor cur = cr.query(SMS_INBOX, projection, where, null, "date desc");  
        if (null == cur)  
            return;  
        if (cur.moveToFirst()) {  
            String number = cur.getString(cur.getColumnIndex("address"));//手機號  
            String body = cur.getString(cur.getColumnIndex("body"));  
            //TODO 這裏是具體處理邏輯 
            
        }  
    }
複製代碼

 

在這裏我們只是寫了一個方法查詢數據庫,但是還有一個問題就是我們應該在什麼時候去查數據庫,總不能起個線程去輪訓,這樣太耗費資源了,這裏我們可以是用觀察者模式;

 

複製代碼
private SmsObserver smsObserver;  
  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.app_login);  
        smsObserver = new SmsObserver(this, smsHandler);  
        getContentResolver().registerContentObserver(SMS_INBOX, true,  
                smsObserver);  
  
    }  
    public Handler smsHandler = new Handler() {  
        //這裏可以進行回調的操作  
        //TODO  
  
    };  
    class SmsObserver extends ContentObserver {  
  
        public SmsObserver(Context context, Handler handler) {  
            super(handler);  
        }  
  
        @Override  
        public void onChange(boolean selfChange) {  
            super.onChange(selfChange);  
            //每當有新短信到來時,使用我們獲取短消息的方法  
            getSmsFromPhone();  
        }  
    }
複製代碼

 

在這裏我們註冊了一個觀察者,監聽收件箱的變化,一旦收件箱變化,我們就查詢數據庫,去除最新的一條數據
相應的權限這裏就不貼出來了
至此我們就實現了通過監聽數據庫的方式來監聽短信內容
 
 

 2.通過廣播監聽短信內容

複製代碼
public class SmsReceiver extends BroadcastReceiver {
    public static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
    private static final String TAG = "yjj";
    public SmsReceiver() {
        Log.i("yjj", "new SmsReceiver");
    }
    @Override
    public void onReceive(final Context context, Intent intent) {
        Log.i(TAG, "jie shou dao");
        Cursor cursor = null;
        try {
            if (SMS_RECEIVED.equals(intent.getAction())) {
                Log.d(TAG, "sms received!");
                Bundle bundle = intent.getExtras();
                if (bundle != null) {
                    Object[] pdus = (Object[]) bundle.get("pdus");
                    final SmsMessage[] messages = new SmsMessage[pdus.length];
                    for (int i = 0; i < pdus.length; i++) {
                        messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                    }
                    if (messages.length > 0) {
                        String content = messages[0].getMessageBody();
                        String sender = messages[0].getOriginatingAddress();
                        long msgDate = messages[0].getTimestampMillis();
                        String smsToast = "New SMS received from : "
                                + sender + "\n'"
                                + content + "'";
                        Toast.makeText(context, smsToast, Toast.LENGTH_LONG)
                                .show();
                        Log.d(TAG, "message from: " + sender + ", message body: " + content
                                + ", message date: " + msgDate);
                        //自己的邏輯
                    }
                }
                cursor = context.getContentResolver().query(Uri.parse("content://sms"), new String[] { "_id", "address", "read", "body", "date" }, "read = ? ", new String[] { "0" }, "date desc");
                if (null == cursor){
                    return;
                }
                Log.i(TAG,"m cursor count is "+cursor.getCount());
                Log.i(TAG,"m first is "+cursor.moveToFirst());
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "Exception : " + e);
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }
    }
}
複製代碼

 

這個很簡單就是定義一個廣播接收者,並且在清單文件中註冊(註冊有兩種方式,這裏就不展開了)

複製代碼
<receiver android:name=".message.SmsReceiver" android:permission="android.permission.BROADCAST_SMS">
            <intent-filter android:priority="2147483647">
                <action android:name="android.provider.Telephony.SMS_DELIVER" />
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
</receiver>
複製代碼

 

3.Android 4.4以上版本短信權限問題

Android4.4版本之前,短信有着一個問題,任何應用只要想,就可以操作短信,着包括監聽短信、修改短信、刪除短信、攔截短信等,因而市面上有着成片的短信應用,着也使得Android系統短信的管理變得越發的混亂。
針對這個問題Google在Android4.4版本之後,引進了一個新的概念----默認短信應用。即用戶可以在系統中選擇由哪個應用默認對短信進行處理。
針對Android4.4版本的,Google提供了 SMS_DELIVER_ACTION(sms)和 WAP_PUSH_DELIVER_ACTION(MMS)這兩個intent給默認的短信使用,也就是說只有默認短信纔可以收到這兩個廣播,也只有收到這兩個廣播的短信應用纔可以對短信數據庫機型操作,其他的短信應用可以使用SMS_RECEIVED_ACTION對短信進行監聽,但僅僅只能讀取(理論上可以監聽,但是在一臺6.0系統的三星機器上並不能監聽到,具體什麼原因沒查出來,當然這是在我所寫的應用沒有成爲手機默認短信應用的情況下,當設置爲默認短信應用後監聽也是正常的)
另外,值得一提的是,在Android4.4版本之前SMS_RECEIVED_ACTION是一個有序廣播,這意味着在Android4.4版本之前,應用在接受廣播之後可以對廣播進行攔截;但是在Android4.4之後,這個攔截動作不會生效,這就意味着Android4.4之後,非默認短信應用對短信除了讀操作外,沒有更多的權限了

 

 

4.Android4.4版本以上設置默認短信應用

我們已經分析了Android4.4版本之後短信的改變----默認短信應用,但是並不是每個應用都可以被設置爲默認短信應用,接下來我們來實現一下怎麼讓我們的短信應用可以被設置爲默認短息應用。
複製代碼
<!-- BroadcastReceiver that listens for incoming MMS messages -->
        <receiver android:name=".message.MmsReceiver"
            android:permission="android.permission.BROADCAST_WAP_PUSH">
            <intent-filter>
                <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
                <data android:mimeType="application/vnd.wap.mms-message" />
            </intent-filter>
        </receiver>
        <!-- Activity that allows the user to send new SMS/MMS messages -->
        <activity android:name=".message.ComposeSmsActivity" >
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <action android:name="android.intent.action.SENDTO" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </activity>
        <!-- Service that delivers messages from the phone "quick response" -->
        <service android:name=".message.HeadlessSmsSendService"
            android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </service>
複製代碼

 

首先我們子在清單文件中寫入如下信息,可以看到我們定義了一個MmsReceiver、一個ComposeSmsActivity、一個HeadlessSmsSendService
很顯然我們需要這三個對應的java文件,即一個receiver類、一個service類、一個Activity類;這三個了都可以不需要任何內容,具體代碼如下
MmsReceiver.java
public class MmsReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    }
}

 

ComposeSmsActivity.java

複製代碼
public class ComposeSmsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
    }
}
複製代碼

 

HeadlessSmsSendService.java

複製代碼
public class HeadlessSmsSendService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
複製代碼

 

通過以上步驟,我們所寫的應用就可以被設置爲默認短信應用了

最後別忘了添加相應的權限:

複製代碼
<uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.WRITE_SMS" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
複製代碼

 

這裏貼出的是我整個項目的權限,世紀應該只需要SMS相關的權限,這裏就不做區分了

下面貼出參考的相關博客,供大家全面瞭解Android短信機制:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章