4.4之後,新增了壹個default sms的機制,詳細的描述,可以參考我的另壹篇文章《談談4.4中的新增功能對安全類軟件的影響》。簡而言之,就是如果要在4.4之後實現短信攔截功能,就必須成為default sms,把所有短信相關的功能都包攬了,然後再做短信攔截。但這種做法,適配性和兼容性的工作是非常巨大的,短信、wapush(多種)、彩信、單雙卡等等,相當於要求短信攔截類的軟件要集成壹個功能非常完善的通訊錄類應用的功能。
那麽,是否有壹種方法,可以在不成為default sms的同時也可以對短信進行“寫操作”(這可是讓4.4壹下子回到解放前啊。。。。)? 答案是有的。
XDA大牛有人發現了壹種比較討巧的方法,原文可以參考這裏。
原理很簡單,主要是利用4.2+後的添加的App Ops權限管理功能,在MESSAGE的TAB中找到自己的App,並進入相應的權限管理界面,如下圖所示,FinalDemo是我自己測試的壹個DEMO:
留意到Write SMS/MMS的開頭,默認是OFF的,但我們可以把它打開。
打開之後,我們就可以通過監控短信數據庫變化的方法實現短信攔截了,我也寫了個簡單的測試代碼,測試成功,把代碼和相關的配置也放了來吧
打開App Ops的代碼
[java] view plaincopy
<span style="white-space:pre"> </span>Intent intent = new Intent(Intent.ACTION_MAIN);
ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.Settings");
intent.setComponent(cn);
intent.putExtra(":android:show_fragment", "com.android.settings.applications.AppOpsSummary");
startActivity(intent);
AndroidManifest.xml的配置
[html] view plaincopy
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="/apk/res/android"
package="com.example.finaldemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<!-- <uses-permission android:name="android.permission.SEND_SMS"/> -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.finaldemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".SmsReceiver"
android:permission="android.permission.BROADCAST_SMS" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<service android:name="com.example.finaldemo.SmsService" />
</application>
</manifest>
短信攔截的代碼
[java] view plaincopy
mObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(Uri.parse("content://sms/inbox"), new String[] { "_id", "address", "body" }, null, null, "_id desc");
long id = -1;
if (cursor.getCount() > 0 && cursor.moveToFirst()) {
id = cursor.getLong(0);
String address = cursor.getString(1);
String body = cursor.getString(2);
Toast.makeText(SmsService.this, String.format("address: %s\n body: %s", address, body), Toast.LENGTH_SHORT).show();
}
cursor.close();
if (id != -1) {
int count = resolver.delete(Sms.CONTENT_URI, "_id=" + id, null);
Toast.makeText(SmsService.this, count == 1 ? "刪除成功" : "刪除失敗", Toast.LENGTH_SHORT).show();
}
}
};
getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, mObserver);
個人結論
在4.4上我們可以在不成為default sms的前提下實現短信攔截,但由於App Ops從4.3出現到4.4壹直牌隱藏的狀態,猜想google還在不斷調整中,4.4之後的子版本是否會保留,是完全不能保證的;
Write SMS/MMS的權限開關的存在跟defaultsms本身是壹個矛盾,之所以出現Write SMS/MMS的權限開關,完全是因為App Ops出現在前,而defaultsms出現在後所致;
在4.4前,短信攔截都是通過動態註冊高優先級BroadcastReceiver的方式進行攔截的,主要是用於跟競品進行短信搶占。而現在ContenetObserver是並行通知的情況下,如果過濾邏輯不夠快,依然有可能會被競品搶先把短信先刪除掉,導致拿到的最後壹次短信是舊的短信。建議結合BroadcastReceiver和ContenetObserver進行攔截,BroadcastReceiver做內容校正和後備數據,以防拿到的最後壹條短信是舊的時候,依然可以進行正常的攔截流程