关于android4.4及以上版本无法恢复还原短信的问题记录与解决
2017-04-29 11:56
671 查看
前段时间在公司项目有系统短信备份和恢复的功能,在4.4(也就是API 19)以下的版本一点问题没有,很简单,没啥好说的,但是在4.4以上以及5.1由于系统更新了 SMS 的部分API,加强了权限控制,因此现在只有default SMS app才能对短信数据库有写权限,但是用户可以把第三方应用设置为default SMS app。也就是说非default
SMS app也能读写短信,只不过是不能写入短信数据库中,这也就直接导致在4.4以上短信无法恢复。没办法,功能肯定还得完成,于是在我在搜索研究后发现了如下解决办法,希望对同样遇到这个问题的人有所帮助。
首先,在4.4以上和5.0以下可以利用权限管理功能(Application Operations)也就是来默认开启写短信的权限,但是坑爹的问题又来了,这个功能被谷歌给隐藏了,因此只能使用反射来搞定,具体做法如下:
一、检查写入短信权限是否已开启,因为有的国产手机,比如魅族,由于它们定制过系统,所以很有可能已经默认开启这个权限了。反射调用AppOpsManager类里的函数 int checkOp(int op, int uid, String packageName),其中op为15就是代表短信写入权限,代码如下:
[java] view
plain copy
@TargetApi(Build.VERSION_CODES.KITKAT)
private int checkMode(){
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
Class c = appOps.getClass();
try {
Class[] cArg = new Class[3];
cArg[0] = int.class;
cArg[1] = int.class;
cArg[2] = String.class;
Method lMethod = c.getDeclaredMethod("checkOp", cArg);
return (Integer) lMethod.invoke(appOps, 15, Binder.getCallingUid(), getPackageName());
} catch(NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
二、上述checkMode()方法,返回 0 就代表有权限,1代表没有权限,-1代表函数出错了。此时如果返回0,表示没有开启,同样反射调用setMode函数,方法如下:
[java] view
plain copy
private boolean setMode(){
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
Class c = appOps.getClass();
Class[] cArg = new Class[4];
cArg[0] = int.class;
cArg[1] = int.class;
cArg[2] = String.class;
cArg[3] = int.class;
Method lMethod;
try {
lMethod = c.getDeclaredMethod("setMode", cArg);
lMethod.invoke(appOps, 15, Binder.getCallingUid(), getPackageName(),AppOpsManager.MODE_ALLOWED);
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
至此,在4.4以上以及5.0以下的就又可以愉快的恢复短信,写入短信到短信数据库了,细心的朋友可以注意到了,这个是5.0以下能用,没错,非常不幸,在5.0以上这种方法又行不通了(此刻内心早已经把谷歌祖宗八代都默默问候了下),没办法,继续折腾,最后发现在5.0以上只能通过弹框来让用户选择默认短信应用,临时的设置自己的应用为Default
SMS app,临时获取一次写入短信数据库数据能力,等短信恢复完成再改回原来的应用为Default SMS app。,就是类似这种:
做法如下:
1、获取默认App的包名并保存。
[java] view
plain copy
String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(context);
2、让用户修改你的app为Default SMS app。
[java] view
plain copy
Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, context.getPackageName());
startActivity(intent);
3、恢复完短信,再让用户修改回Default SMS app,使用第一步保存的包名。
[java] view
plain copy
Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp);
startActivity(intent);
接下来,要将自己的应用设置为默认短信应用必须按照下面的步骤来,一样都不能少,不然成功不了,操作如下:
1、首先在清单文件里做如下配置(一个都不能少):
[java] view
plain copy
<receiver android:name="com.boy.pro.defaultsms.SmsReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<receiver android:name="com.boy.pro.defaultsms.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 android:name="com.boy.pro.defaultsms.SmsActivity" >
<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 android:name="com.boy.pro.defaultsms.SmsService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:exported="true" >
<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>
2、然后按照清单文件里的新建对应的类,类里面可以什么都不用写,如下图:
至此,写入短信到短信数据库,恢复短信的功能就完成了,有需要的人拿去吧!
SMS app也能读写短信,只不过是不能写入短信数据库中,这也就直接导致在4.4以上短信无法恢复。没办法,功能肯定还得完成,于是在我在搜索研究后发现了如下解决办法,希望对同样遇到这个问题的人有所帮助。
首先,在4.4以上和5.0以下可以利用权限管理功能(Application Operations)也就是来默认开启写短信的权限,但是坑爹的问题又来了,这个功能被谷歌给隐藏了,因此只能使用反射来搞定,具体做法如下:
一、检查写入短信权限是否已开启,因为有的国产手机,比如魅族,由于它们定制过系统,所以很有可能已经默认开启这个权限了。反射调用AppOpsManager类里的函数 int checkOp(int op, int uid, String packageName),其中op为15就是代表短信写入权限,代码如下:
[java] view
plain copy
@TargetApi(Build.VERSION_CODES.KITKAT)
private int checkMode(){
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
Class c = appOps.getClass();
try {
Class[] cArg = new Class[3];
cArg[0] = int.class;
cArg[1] = int.class;
cArg[2] = String.class;
Method lMethod = c.getDeclaredMethod("checkOp", cArg);
return (Integer) lMethod.invoke(appOps, 15, Binder.getCallingUid(), getPackageName());
} catch(NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return -1;
}
二、上述checkMode()方法,返回 0 就代表有权限,1代表没有权限,-1代表函数出错了。此时如果返回0,表示没有开启,同样反射调用setMode函数,方法如下:
[java] view
plain copy
private boolean setMode(){
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
Class c = appOps.getClass();
Class[] cArg = new Class[4];
cArg[0] = int.class;
cArg[1] = int.class;
cArg[2] = String.class;
cArg[3] = int.class;
Method lMethod;
try {
lMethod = c.getDeclaredMethod("setMode", cArg);
lMethod.invoke(appOps, 15, Binder.getCallingUid(), getPackageName(),AppOpsManager.MODE_ALLOWED);
return true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
至此,在4.4以上以及5.0以下的就又可以愉快的恢复短信,写入短信到短信数据库了,细心的朋友可以注意到了,这个是5.0以下能用,没错,非常不幸,在5.0以上这种方法又行不通了(此刻内心早已经把谷歌祖宗八代都默默问候了下),没办法,继续折腾,最后发现在5.0以上只能通过弹框来让用户选择默认短信应用,临时的设置自己的应用为Default
SMS app,临时获取一次写入短信数据库数据能力,等短信恢复完成再改回原来的应用为Default SMS app。,就是类似这种:
做法如下:
1、获取默认App的包名并保存。
[java] view
plain copy
String defaultSmsApp = Telephony.Sms.getDefaultSmsPackage(context);
2、让用户修改你的app为Default SMS app。
[java] view
plain copy
Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, context.getPackageName());
startActivity(intent);
3、恢复完短信,再让用户修改回Default SMS app,使用第一步保存的包名。
[java] view
plain copy
Intent intent = new Intent(context, Sms.Intents.ACTION_CHANGE_DEFAULT);
intent.putExtra(Sms.Intents.EXTRA_PACKAGE_NAME, defaultSmsApp);
startActivity(intent);
接下来,要将自己的应用设置为默认短信应用必须按照下面的步骤来,一样都不能少,不然成功不了,操作如下:
1、首先在清单文件里做如下配置(一个都不能少):
[java] view
plain copy
<receiver android:name="com.boy.pro.defaultsms.SmsReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter>
</receiver>
<receiver android:name="com.boy.pro.defaultsms.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 android:name="com.boy.pro.defaultsms.SmsActivity" >
<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 android:name="com.boy.pro.defaultsms.SmsService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:exported="true" >
<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>
2、然后按照清单文件里的新建对应的类,类里面可以什么都不用写,如下图:
至此,写入短信到短信数据库,恢复短信的功能就完成了,有需要的人拿去吧!
相关文章推荐
- 关于android4.4及以上版本无法恢复还原短信的问题记录与解决
- 如何解决在android4.4系统中无法正常恢复短信
- 关于note2等(Android4.1版本)以上无法启动支付宝的问题"java.security.spec.InvalidKeySpecException"
- 针对Android4.4以上版本,通过uri获取 data为null问题解决方案
- mysql 5.7以上免安装版本无法找到data文件夹问题的解决办法
- 解决.net 2.0以上版本GDI+绘图保存后在Photoshop中无法识别的问题
- 关于50.0版本以上浏览器无法添加使用firebug的解决办法
- 关于CCS6以上版本IDE无法进行软仿真的问题
- 关于ClickOnce无法更新/Upgrade/下载 应用系统最新版本的问题和解决方法
- 彻底解决ubuntu环境下,Qt5.5以上版本无法进行中文注释的问题。
- 解决4.4版本以上剪裁图片时提示无法加载图片的问题
- 解决eclipse3.4以上版本手动安装subcplise插件无法启用问题
- 【机智】Android 微信6.2以上版本 转移聊天记录到ios,当前Wi-Fi环境复杂,无法传输 问题
- 转://【MOS】关于在不同版本和平台之间进行还原或复制的常见问题 (文档 ID 1526162.1)--跨版本恢复
- 解决Qt5.2及以上版本无法连接64位mysql问题
- 解决jdk1.4生成二维码问题,因为现下生成二维码的jar包,版本最低支持jdk1.5以上的版本,老的项目中想使用二维码,直接使用jar包无法使用
- 关于Android4.4以上版本的外置存储器路径问题
- 关于resin3以上版本不能运行struts1.2程序的问题解决办法
- 解决ununtu 8.04版本以上回收站无法删除问题
- 使用DotNetNuke(DNN) Startkit 4.7(及以上版本)安装无法完成问题的解决方法