1. 程式人生 > >利用ContentProvider讀取系統應用的資訊(簡訊和聯絡人)

利用ContentProvider讀取系統應用的資訊(簡訊和聯絡人)

上面兩篇我們講了ContentProvider如何使用

Android進階:步驟2:ContentProvider初體驗

Content Provider 解析URI的方法 UriMatcher的用法和自帶的解析方法

1.現在我們將如何通過某一個應用讀系統短訊息

系統簡訊箱的Uri分成以下幾個部分

  • content://sms 簡訊箱
  1. content://sms/inbox 收信箱
  2. content://sms/sent 發信箱
  3. content://sms/draft  草稿箱

可以跟你你想要拿的信箱加以區分

讀取信箱分成以下三個步驟:

在內容處理者(ContentResolver)中處理

1.配置檔案中新增讀寫信箱的許可權,和android6.0後動態申請許可權

2.獲取內容處理者物件

3.查詢方法返回Cursor物件

4.解析Cursor

程式碼:

AndroidManifest.xml中新增讀資訊的許可權

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

android6.0後要動態申請許可權

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ContentResolver contentResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.申請許可權 在配置檔案中寫還有動態申請
        checkPermission(this);
        //2拿的內容處理者物件
        contentResolver = getContentResolver();
        findViewById(R.id.sms_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //拿的發信箱的uri
                Uri uri = Uri.parse("content://sms/sent");
                //引數1:uri
                //引數2:查詢指定列範圍,null為查詢所有
                //引數3:查詢條件,不指定
                //引數4:查詢條件陣列,和引數2搭配使用,不指定
                //引數5:排序
                Cursor c = contentResolver.query(uri, null, null, null, null);
                //3.解析Uri
                //遍歷Cursor
                while (c.moveToNext()) {
                    String msg = "";
//                    //顯示每條發信箱的內容
//                    //遍歷該行的列
//                    for(int i=0;i<c.getColumnCount();i++){
//                        msg+=c.getString(i)+" ";
//                    }
                    //如果只有拿接收者號碼和資訊內容
                    //系統指定的列名分別為 address body
                    String address = c.getString(c.getColumnIndex("address"));
                    String body = c.getString(c.getColumnIndex("body"));
                    msg = address + " " + body;
                    Log.e("TAG", "msg=" + msg);
                }
            }
        });
    }

    //android6.0之後要動態獲取許可權
    private void checkPermission(Activity activity) {
        // Storage Permissions
        final int REQUEST_EXTERNAL_STORAGE = 1;
        String[] PERMISSIONS_STORAGE = {
                Manifest.permission.READ_SMS,
        };

        try {
            //檢測是否有讀簡訊箱的許可權
            int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_SMS");
            if (permission != PackageManager.PERMISSION_GRANTED) {
                // 沒有讀簡訊箱的許可權,去申請寫的許可權,會彈出對話方塊
                ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Log列印結果:

這是我發信箱的簡訊

 

拿到的簡訊:

 E/TAG: msg=95559 66666
    msg=10086 ???

2.讀取聯絡人

讀取聯絡人和讀取簡訊的類似

但稍微有點複雜,因為聯絡人的姓名和電話號碼是放在不同的兩個表的,需要進行兩次查詢

聯絡人姓名是主表,id是主鍵,電話號碼所在的表是從表,可以通過主表的id主鍵來查到對應從表的電話號碼

步驟:

1.新增許可權

2.查詢操作,返回Cursor

3.解析Cursor

程式碼:

1.新增許可權

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

6.0後動態申請許可權寫在一起了後面就不寫了 

    //android6.0之後要動態獲取許可權
    private void checkPermission(Activity activity) {
        // Storage Permissions
        final int REQUEST_EXTERNAL_STORAGE = 1;
        String[] PERMISSIONS_STORAGE = {
                Manifest.permission.READ_SMS,
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.WRITE_CONTACTS
        };

        try {
            //檢測是否有讀簡訊箱的許可權
            int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_SMS");
           //檢查是否有讀聯絡人的許可權
            int permission2 = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.READ_CONTACTS");
            //檢查是否有寫聯絡人的許可權
            int permission3 = ActivityCompat.checkSelfPermission(MainActivity.this,
                    "android.permission.WRITE_CONTACTS");
            if (permission != PackageManager.PERMISSION_GRANTED ||
                permission2!= PackageManager.PERMISSION_GRANTED ||
                    permission3 != PackageManager.PERMISSION_GRANTED) {
                // 沒有某一個許可權,去申請相應許可權,會彈出對話方塊
                ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    findViewById(R.id.read_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //對應聯絡人而言,他們的儲存方式是將姓名和其他內容(電話號碼)由不同的ContentProvider操作的
                //首先想象聯絡人和其他內容屬於不同的表
                //而姓名所在的表示主表,其他內容位於從表
                //而主表的主鍵id在從表中作為外來鍵使用
                //1.查姓名的uri
                Uri uri1 = ContactsContract.Contacts.CONTENT_URI;
                Cursor c1 = contentResolver.query(uri1, null, null, null, null);
                while (c1.moveToNext()) {
                    //姓名的列
//                ContactsContract.Contacts.DISPLAY_NAME;
//                //主鍵id的列
//                ContactsContract.Contacts._ID;
                    //同樣可以遍歷所有列,但這裡只要看姓名和電話
                    String name = c1.getString(c1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                    String id = c1.getString(c1.getColumnIndex(ContactsContract.Contacts._ID));

                    //繼續訪問下一個Uri拿到對應從表的電話號碼
                    //2.查詢電話的Uri
                    Uri uri2 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
                    //在從表外來鍵id的查詢條件
                    String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?";
                    //通過這個外來鍵找到相應的電話號碼
                    Cursor c2 = contentResolver.query(uri2,
                            null,
                            selection,//查詢條件
                            new String[]{id},//查詢條件的值
                            null);
                    //每一id(一個人)都可以有多個電話號碼
                    //還有要將每個電話號碼拿出來
                    while (c2.moveToNext()) {
                        //取出電話號碼的列
                        String number = c2.getString(c2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        name += " 電話:" + number;
                    }
                    Log.e("TAG", "姓名是:" + name + " id是:" + id);
                }
            }
        });

輸出結果:

E/TAG: 姓名是:Cmcc 電話:1 387-891-2345 id是:1
E/TAG: 姓名是:Love 電話:1 827-891-2345 電話:1 527-891-2345 id是:2

如果僅僅查詢某個人的電話

更改一個查詢的語句,新增上查詢條件

Cursor c1 = contentResolver.query(
uri1,
null, 
ContactsContract.Contacts.DISPLAY_NAME+"=?",//查詢條件
 new String[]{"Love"},//查詢條件值陣列
 null);

就會只顯示Love的電話

E/TAG: 姓名是:Love 電話:1 827-891-2345 電話:1 527-891-2345 id是:2

 3.新增聯絡人

上面許可權的就不寫了,在上一個獲取聯絡人

  findViewById(R.id.add_contact_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //1.往一個ContentProvider中插入一條空資料,獲取新的id
                //2.利用剛剛生成的id分別組合姓名和電話號碼往另一個ContentProvider插入資料
                ContentValues values=new ContentValues();
                //拿到插入空資料的uri
                Uri uri=ContactsContract.RawContacts.CONTENT_URI;
                //返回的uri後面追加有id
                Uri returnUri=contentResolver.insert(uri,values);
                //獲取這個id
                long id= ContentUris.parseId(returnUri);

                //插入姓名
                //獲取插入姓名的Uri
                Uri nameUri=ContactsContract.Data.CONTENT_URI;
                //放姓名的列名
                values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,"新聯絡人");
                //放id的列名
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定新增的新增的資料型別(在ContentProvider 有一個獲取型別的方法)
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
                contentResolver.insert(nameUri,values);

                //插入電話號碼
                //先清空之前的資料
                values.clear();
                //插電話號碼
                values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,"13878999999");
                //放id的列名
                values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
                //指定資料型別
                values.put(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
                //對於電話號碼,可能是手機號或者是座機號碼
                //所以要指定電話號碼的型別是行動電話
                values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
                contentResolver.insert(ContactsContract.Data.CONTENT_URI,values);
            }
        });

效果演示