Android新姿式:如何截取短信

公司要作一個【由於是機密因此不能說】的項目,有個需求是攔截手機系統的短信,並且不能在手機的短信應用上顯示。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;
			}
		}
	}
}
相關文章
相關標籤/搜索