2014-12-29 17 views
9

Tôi đang cố gắng tạo ứng dụng Android viết thư trong Hộp đã gửi của hệ thống. Các tin nhắn này không được gửi qua mạng GSM đến người nhận, ý tưởng chỉ để viết chúng trong Nhà cung cấp nội dung đã gửi.Android KitKat (API 19) - Cách viết tin nhắn trong Nhà cung cấp nội dung SMS, không gửi chúng, từ Ứng dụng không mặc định?

Còn bây giờ, tôi có mã này:

Manifest file

<uses-permission android:name="android.permission.READ_SMS"/> 
<uses-permission android:name="android.permission.WRITE_SMS"/> 

Java Class

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); 

Đối với một thiết bị với một phiên bản API thấp hơn 19, điều này triển khai hoạt động tốt. Đối với các phiên bản sdk cũ hơn, chỉ cần truy cập vào nhà cung cấp nội dung được xác định bởi nội dung uri : // sms/sent.

Đối với các phiên bản sdk mới hơn, tính năng này không hoạt động. Rõ ràng, Android đã thay đổi cách quản lý mô-đun SMS trong bản phát hành KitKat. Theo bài viết tiếp theo, chỉ ứng dụng SMS mặc định mới có thể viết và cập nhật Nhà cung cấp nội dung SMS mới (android.provider.Telephony.Sms.Sent - nội dung trước đó: // sms/sent cũng không khả dụng):

Xem xét hành vi của ứng dụng này, việc chuyển ứng dụng SMS mặc định là không có ý nghĩa. Ứng dụng này không cần đọc tin nhắn SMS từ nhà cung cấp nội dung và không được gửi bất kỳ tin nhắn nào bằng SmsManager.getDefault(). SendTextMessage. Điều duy nhất cần làm là viết một số tin nhắn trong Nhà cung cấp đã gửi.

Như bạn có thể hiểu, nó cũng không được chấp nhận và có thể thực hiện để yêu cầu người dùng thay đổi ứng dụng mặc định thành của tôi và sau đó quay lại ứng dụng SMS trước đó, mỗi khi cần viết tin nhắn trong Sent (điều này được đề xuất trong phần "Lời khuyên cho SMS backup & khôi phục ứng dụng" trong Blogspot của nhà phát triển Android).

Trong phần tiếp theo cho thấy một số cách để thôi ẩn các OP_WRITE_SMS tùy chọn:

Thật không may, các mã tiếp theo ngừng làm việc dành cho Android 4.4.2:

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); 

tôi ra khỏi các giải pháp để khắc phục vấn đề này.

+0

Thư mục đã gửi không chỉ phản ánh các thư đã được gửi (hoặc ít nhất là cố gắng) và không phải là thư "giả mạo" chưa? –

Trả lời

15

Lớp SmsWriteOpUtils sử dụng phản ánh để truy cập các phương thức của AppOpsManager Dịch vụ để bật/tắt quyền truy cập ghi của ứng dụng SMS không mặc định cho Nhà cung cấp SMS ở cấp API 19 (KitKat). Sau khi được đặt, chế độ truy cập của ứng dụng sẽ được giữ lại cho đến khi được đặt lại hoặc ứng dụng được gỡ cài đặt.

Bật quyền truy cập ghi của ứng dụng cho phép ứng dụng đó tất cả các phương pháp tương tác chuẩn với Nhà cung cấp SMS, bao gồm insert()delete().

Xin lưu ý rằng lớp học này không kiểm tra cấp API và yêu cầu quyền đối với số 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, 
                   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", 
                   Integer.TYPE, 
                   Integer.TYPE, 
                   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, WRITE_OP_CODE, uid, packageName, mode); 

      return true; 
     } 
     catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
     return false; 
    } 
} 

sử dụng Ví dụ:

boolean canWriteSms; 

if(!SmsWriteOpUtils.isWriteEnabled(getApplicationContext())) { 
    canWriteSms = SmsWriteOpUtils.setWriteEnabled(getApplicationContext(), true); 
} 
... 

NB: Đối với các ứng dụng sử dụng thường xuyên, điều này chỉ hoạt động trên API Level 19 (KitKat). Lỗ được vá trong các phiên bản sau.

+1

Điều này làm việc hoàn hảo! Tôi đã thử nghiệm trên thiết bị Android 4.4.4 mà tôi cũng có ở đây. Tôi sẽ cố gắng thực hiện điều này trong bản phát hành Lollipop trong những ngày tiếp theo. Cảm ơn! – supertreta

+0

Vẫn không thể xóa sms – xnagyg

+0

@xnagyg Bạn có nhớ sự cho phép của 'WRITE_SMS' không? Bạn có thể chèn tin nhắn không? Giá trị trả về cho phương thức 'public static' là gì? Mã xóa của bạn có hoạt động trên phiên bản trước KitKat không? Bạn đang thử nghiệm thiết bị và phiên bản Android nào? Tôi có một cái testbed giới hạn, nhưng mọi thứ đều phù hợp với tôi, và, rõ ràng, OP. –

Các vấn đề liên quan