我最近有個短信讀取與恢復的需求,現(xiàn)在對其核心實現(xiàn)進行以下總結(jié)。
一、短信讀取
fun getAllSms(context: Context) {
val cv = context.contentResolver
val cursor =
cv.query(Telephony.Sms.CONTENT_URI, null, null, null, Telephony.Sms.DEFAULT_SORT_ORDER)
if (cursor == null) {
Log.e(TAG, "cursor is null")
return
}
while (cursor.moveToNext()) {
val type = cursor.getInt(cursor.getColumnIndex(Telephony.Sms.TYPE))
val address = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS))
val date = cursor.getLong(cursor.getColumnIndex(Telephony.Sms.DATE))
val body = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY))
val person = cursor.getInt(cursor.getColumnIndex(Telephony.Sms.PERSON))
val protocol = cursor.getInt(cursor.getColumnIndex(Telephony.Sms.PROTOCOL))
Log.i(TAG, "sms = " + Sms(type, address, date, body, person, protocol).toString())
}
cursor.close()
}
二、設置系統(tǒng)默認短信APP
從Android5.0開始,默認短信應用外的軟件不能以寫入短信數(shù)據(jù)庫的形式(write sms)發(fā)短信,也就是說插入短信到短信數(shù)據(jù)庫方法行不通了。
我的解決方法是將應用設置為默認短信(事實上,并沒有成為真正的短信App,只是應用現(xiàn)在具有了創(chuàng)建短信的能力了,就滿足我的需求了),操作如下:
0、首先要進行如下配置
這些配置是系統(tǒng)任務一個短信App應該有的功能,要想設置成默認短信App,就必須得有這些。當然創(chuàng)建一個空的就可以,因為我目前的需求是設置成默認短信App,然后能創(chuàng)建短信就行。
<!-- 接收SMS -->
<receiver
android:name=".SmsReceiver"
android:exported="false"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<!-- 接收MMS-->
<receiver
android:name=".MmsReceiver"
android:exported="false"
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>
<service
android:name=".HeadlessSmsSendService"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
<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>
<activity
android:name=".activity.MainActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<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>
這里我還遇到了一個問題:我在MainActivity中添加了一系列配置后,圖標消失了。解決方法是將這些配置移到另一個Activity中就可以了。
然后開始設置應用為默認短信。在進行了一系列搜索后與試驗后,最后終于在Rolemanager的源碼注釋中找到了答案:
1、Android29及以上
Then the application will need user consent to become a role holder, which can be requested using android.app.Activity.startActivityForResult(Intent, int) with the Intent obtained from createRequestRoleIntent(String).
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val rm = SystemServiceHelper.getRoleManager() as RoleManager
val intentSms = rm.createRequestRoleIntent(RoleManager.ROLE_SMS)
startActivityForResult(intentSms, REQUEST_CODE_DEFAULT_SMS)
}
/**
* 獲取 RoleManager,用于指定默認的應用
*/
@RequiresApi(Build.VERSION_CODES.Q)
fun getRoleManager(): RoleManager? {
val rm =
AppContext.appContext.getSystemService(Context.ROLE_SERVICE) as RoleManager?
if (rm == null) {
Log.e(TAG, "[RoleManager is null]")
}
return rm
}
核心在于:createRequestRoleIntent。
2、低版本設置
val defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(this)
if (packageName != defaultSmsApp) {
val intent = Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT)
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, packageName)
startActivity(intent)
}
三、創(chuàng)建短信
fun addSms(context: Context) {
val cv = context.contentResolver
var value = ContentValues()
value.put(Telephony.Sms.BODY, "測試短信創(chuàng)建")
value.put(Telephony.Sms.PERSON, 11111111111)
value.put(Telephony.Sms.ADDRESS, "11111111111")
value.put(Telephony.Sms.DATE, System.currentTimeMillis())
value.put(Telephony.Sms.TYPE, 1)
value.put(Telephony.Sms.READ, 0)
cv.insert(Telephony.Sms.CONTENT_URI, value)
}
小結(jié)
1、需要注意的是,像上面這樣設置過后,我們的應用就有了創(chuàng)建短信的能力,但事實上,我們的App還不是默認應用。(有需求的朋友可以繼續(xù)探索一下)
參考
1、Android 讀取所有短信
2、android黑科技之讀取用戶短信+插入短信到系統(tǒng)短信數(shù)據(jù)庫
3、Android設為系統(tǒng)默認的短信應用
在 Android11(小米)上,沒有生效
4、Android如何將第三方信息應用設置為默認信息應用?
5、Android10.0(Q) 默認應用設置(電話、短信、瀏覽器、主屏幕應用)
4/5反射方式,都報錯:Caused by: java.lang.SecurityException: addRoleHolderAsUser: Neither user 10318 nor current process has android.permission.MANAGE_ROLE_HOLDERS.
這個權限申請不到,因此這兩種方案不適合。