公司要作一个【由于是机密因此不能说】的项目,有个需求是拦截手机系统的短信,并且不能在手机的短信应用上显示。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; } } } }