现在,我有这个代码:
清单文件
<uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.WRITE_SMS"/>
Java类
private final String SENT_SMS_CONTENT_PROVIDER_URI_OLDER_API_19 = "content://sms/sent"; ContentValues values = new ContentValues(); values.put("address",mNumber); values.put("body",mMessage); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) mContext.getContentResolver().insert(Telephony.Sms.Sent.CONTENT_URI,values); else mContext.getContentResolver().insert(Uri.parse(SENT_SMS_CONTENT_PROVIDER_URI_OLDER_API_19),values);
对于API版本低于19的设备,此实现工作正常.对于这些较旧的sdk版本,只需要访问由uri内容定义的内容提供者:// sms / sent.
对于较新的sdk版本,这不工作.显然,Android改变了在KitKat版本中管理SMS模块的方式.根据下一篇文章,只有默认的SMS应用程序可以编写和更新新的SMS内容提供程序(android.provider.Telephony.Sms.Sent – 以前的内容:// sms / sent也不可用):
> http://android-developers.blogspot.pt/2013/10/getting-your-sms-apps-ready-for-kitkat.html
考虑到这个应用程序的行为,把默认的短信应用程序变成没有意义.此应用程序不需要从内容提供商读取SMS消息,不应通过SmsManager.getDefault().sendTextMessage发送任何消息.它应该做的唯一的事情是在发送提供程序中写入一些消息.
您可以理解,请求用户将默认应用更改为我的,然后返回到上一个SMS应用程序,每次有必要在Sent中写入消息(这是建议在Android Developers Blogspot中的“备份和恢复应用程序的建议”部分).
下一篇文章揭示了一些取消隐藏选项OP_WRITE_SMS的方法:
新新200新200新200新新旗新新新新新新新新新新新旗新旗新200新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新旗新新
Intent intent = new Intent(); intent.setClassName("com.android.settings","com.android.settings.Settings"); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); intent.putExtra(":android:show_fragment","com.android.settings.applications.AppOpsSummary"); startActivity(intent);
X- 20045 X- 200 X- 200 200 X- 200 200:
解决方法
启用应用程序的写访问权限允许应用程序与SMS提供程序进行交互的所有标准方法,包括insert()和delete().
请注意,此类不执行API级别检查,并且仍需要WRITE_SMS权限.
import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public final class SmsWriteOpUtils { private static final int WRITE_OP_CODE = 15; public static boolean isWriteEnabled(Context context) { int result = checkOp(context); return result == AppOpsManager.MODE_ALLOWED; } public static boolean setWriteEnabled(Context context,boolean enabled) { int mode = enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED; return setMode(context,mode); } private static int checkOp(Context context) { try { Method checkOpMethod = AppOpsManager.class.getMethod("checkOp",Integer.TYPE,String.class); AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int uid = context.getApplicationInfo().uid; String packageName = context.getPackageName(); return checkOpMethod.invoke(appOpsManager,WRITE_OP_CODE,uid,packageName); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } return -1; } private static boolean setMode(Context context,int mode) { try { Method setModeMethod = AppOpsManager.class.getMethod("setMode",String.class,Integer.TYPE); AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); int uid = context.getApplicationInfo().uid; String packageName = context.getPackageName(); setModeMethod.invoke(appOpsManager,packageName,mode); return true; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } return false; } }
使用示例
boolean canWriteSms; if(!SmsWriteOpUtils.isWriteEnabled(getApplicationContext())) { canWriteSms = SmsWriteOpUtils.setWriteEnabled(getApplicationContext(),true); } ...
注意:对于常规用户应用程序,这仅适用于API Level 19(KitKat).孔在以后的版本中修补.