Android4.4及其以上版本限制了第三方短信App的插入数据库的功能,只有默认短信程序才可以进行插入操作,系统也提供了设置界面,用来设置默认短信应用。这样的话,我们的备份应用如果还盲目地getContentResolver().insert
的话,就会发现代码成功执行,但是短信里啥都没有。所以解决办法是,要先把自己的应用设置成默认短信应用,然后再进行插入操作,然后记得把默认短信应用恢复回来。当然这里最主要的步骤就是设置成默认短信应用,因为这需要打开系统界面让用户点了才行。
这里记录一下我所做的过程,关于备份和恢复短信的具体代码这里就不赘述了。
下面分步说明:
- 第一步,注册2个receiver,1个activity,1个service:
<!-- BroadcastReceiver that listens for incoming SMS messages -->
<receiver
android:name=".sms.SmsReceiver"
android:permission="android.permission.BROADCAST_SMS" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<!--BroadcastReceiver that listens for incoming MMS messages-->
<receiver
android:name=".sms.MmsReceiver"
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>
<!--Activity that allows the user to send new SMS/MMS messages-->
<activity
android:name=".sms.ComposeSmsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<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>
<!--Service that delivers messages from the phone "quick response"-->
<service
android:name=".sms.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>
为啥要注册这些?这几个东西能干啥?
这些是收发短信用的,既然你都成为了这个手机的默认短信app了,那你肯定要负责手机的短信相关事务啊,不能光想拿钱不想干活是不是?上面的代码不用做修改,直接放到manifest里面即可,还有一些相关的权限也不用加,因为我们只是稍稍用那么一小会儿,并不打算真的充当一个默认短信应用。
- 第二步,把上面声明的几个类都给写成java类:
啥也不说,alt+enter,按提示都给整出来,一句多的都不用加,看下代码:
public class ComposeSmsActivity extends Activity {
}
public class HeadlessSmsSendService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
public class MmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
上面两步做完后,你才能调起系统的设置界面。
- 第三步,在用户点击“恢复”按钮时给个警告说明:
- 第四步,在点完确定后,打开系统设置界面:
/**
* 系统默认的短信应用保存一下,方便后面还原
*/
private String defaultSmsApp;
//点击"恢复"以后执行的代码
//是否是4.4版本以上,如果不是直接执行恢复代码
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
//获得自己app的包名
String myPackageName = getPackageName();
//获得系统默认短信应用的包名
defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(XXXActivity.this);
//如果自己的app不是默认app的话,就打开设置的界面,否则就直接执行恢复代码
if (!defaultSmsApp.equals(myPackageName)) {
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME,myPackageName);
//这里加ForResult是为了加一个检验是否设置成功的时机
startActivityForResult(intent,101);
//一旦走了这里,就不能执行恢复代码了
return;
}
}
//执行恢复代码
recoverySms();
下面是onActivityResult中的代码
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 101){
//设置默认短信成功
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
final String myPackageName = getPackageName();
if (Telephony.Sms.getDefaultSmsPackage(XXXActivity.this)
.equals(myPackageName)) {
//继续执行恢复代码
recoverySms();
}
}
}
}
这样,就能在用户同意之后继续执行恢复代码了
- 第五步,在恢复结束后,不论成功与否,都应该将默认短信应用还原
下面是恢复结束的代码:
//恢复结束,将默认短信还原
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
String myPackageName = getPackageName();
if (Telephony.Sms.getDefaultSmsPackage(XXXActivity.this)
.equals(myPackageName)) {
Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
//这里的defaultSmsApp是前面保存的
intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp);
startActivity(intent);
}
}
Over,问题解决了。