公司要作一個【由於是機密因此不能說】的項目,有個需求是攔截手機系統的短信,並且不能在手機的短信應用上顯示。php
OK,一開始覺得不難,網上查了一下資料也發現有人作過,因而就開始寫demo,結果才發現,這尼瑪就是個大坑啊!!java
首先網上查到的最多的實現方案是利用自定義的 BroadcastReceiver 去攔截"android.provider.Telephony.SMS_RECEIVED" 的廣播,看起來也不難,因而試了下。發現好坑爹啊!在個人酷派大神上不管怎麼樣就是攔截不到~android
好吧,必定是我寫代碼的姿式不對,因此又到網上查資料。數據庫
嚯嚯嚯,我果真機智~~ 一會兒就找到了!原來是個人優先級不夠。ide
安卓的廣播是有優先級的,而且動態註冊的廣播優先級更高。因而參考網上說的,優先級設到2147483647,又弄個動態註冊,而後興奮的用個人酷派再試一次——但仍是不行!code
詳見:http://www.apkbus.com/forum.php?mod=viewthread&tid=53053 server
鬱悶,難道是我手機的問題?好吧,拿一個同事的2.3安卓機試了一下,還真的能夠。。。難道真是手機問題?不行,多拿幾臺試一下。因而再拿其餘同事的手機了一下,也跟我同樣。那麼大概就能夠肯定了,是手機系統版本不同,由於其餘同事都是4.0以上的手機。blog
好吧雖然緣由找到,但總得想辦法解決是吧?ip
網上關於攔截短信的資料雖然比較少,不過仍是有提到其餘的方法的。另外一個方法就是監聽數據庫發生變化時去刪除短信的數據。也就是在插入新信息的時候把新信息刪了,這樣也算是攔截。get
網上的資料是註冊一個內容提供者監聽"content://sms/" 的數據變化,按照他寫的代碼試了,仍是能夠監聽到數據庫變化的。
詳見:http://bingtian.iteye.com/blog/641566
可是,在4.0以上系統cursor竟然是空的(2.3的手機沒問題)!
TUT好坑爹啊!到底毛回事啊!
好吧,耐心的我又想到另外一個onChange(boolean selfChange, Uri uri),這個帶Uri參數的方法是高版本的安卓系統上纔有的,因此我在這裏把uri打印了出來。結果發現打印出來的都是content://sms/9十、content://sms/911之類的,根本就沒有content://sms/inbox。那麼也怪不得cursor是空的!
好吧,既然content://sms/inbox查不到,那我就查你給個人uri吧~
首先把該uri的字段打印出來:
_id;thread_id;address;m_size;person;date;date_sent;protocol;read;status;type;reply_path_present;subject;body;service_center;locked;sim_id;error_code;seen;ipmsg_id;ref_id;total_len;rec_len;itemInfoid;receive_date;
再跟2.3系統的content://sms/inbox字段對比一下:
_id;thread_id;address;person;date;sc_timestamp;protocol;read;status;type;reply_path_present;subject;body;service_center;locked;error_code;seen;lgeMsgType;lgeSiid;lgeCreated;lgeExpires;lgeReceived;lgeAction;lgeSec;lgeMac;lgeDoc;doInstalled;lgePinRemainCnt;index_on_icc;service_msg_sender_address;modified;modified_time;
有些字段是不同的,不過一些主要的字段如_id、address、body仍是同樣的。
那麼要拿到短信的內容跟發件人的號碼仍是沒問題的,address就是發件人號碼,body是短信內容。試了一下,能夠拿到。
比較擔憂的就是能不能刪除掉數據庫裏的這些短信,不過試了一下仍是能夠的~
就結果而言還不錯——成功的攔截到短信,並把短信刪掉了,系統雖然會「叮~」的一聲提醒來短信了,可是顯示的卻不是我剛發的短信,而是我上一次發的(剛發的已經被刪了)。
總結:既然不能在這棵樹上吊死,就多找幾課樹試試。
部分源碼展現:
public class SmsContent extends ContentObserver{ /**單例*/ private static SmsContent instance; /** * 保證調用一次便可 */ public static void register(Context context){ if (instance==null) { instance = new SmsContent(context, new Handler()); } context.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, instance); } @Override public void onChange(boolean selfChange) { super.onChange(selfChange); try { cursor = context.getContentResolver().query(Uri.parse("content://sms/inbox"), new String[]{"*"}, "_id>?", new String[]{"-1"}, "date desc");//倒序,也就是最新的在第一條 if (cursor != null) { if(cursor.moveToNext()){ String body = cursor.getString(cursor.getColumnIndex("body")); String _id = cursor.getString(cursor.getColumnIndex("_id")); final String address = cursor.getString(cursor.getColumnIndex("address")); L.d("攔截到短信:body="+body+";_id="+_id+";address="+address); …… } }else { } } catch (Exception e) { e.printStackTrace(); }finally{ if(cursor!=null&&!cursor.isClosed()){ cursor.close(); cursor = null; } } } @SuppressLint("NewApi") @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); try { cursor = context.getContentResolver().query(uri, new String[]{"*"}, "_id>?", new String[]{"-1"}, "date desc"); if (cursor != null) { if(cursor.moveToNext()){ String body = cursor.getString(cursor.getColumnIndex("body")); String _id = cursor.getString(cursor.getColumnIndex("_id")); final String address = cursor.getString(cursor.getColumnIndex("address")); L.d("攔截到短信:body="+body+";_id="+_id+";address="+address); …… } }else { } } catch (Exception e) { e.printStackTrace(); }finally{ if(cursor!=null&&!cursor.isClosed()){ cursor.close(); cursor = null; } } } }