ContactsContract.Contacts.CONTENT_URI无法获取手机号码

需求:打开系统联系人,获取手机号码。
可能会遇到的问题:同一个用户多个手机号码
阅读本文会收获2个技能:

  • 学会反编译Apk查看代码实现原理
  • 快速定位反编译后的代码

最开始我以为像类似获取系统图片那样去获取手机号码,很快解决,实际上也不是很难,方法对了就很快。
最开始根据Action事件在startActivityForResult中找到官方的文档说明(毕竟我觉得这种应该很容易去实现,一个Action就可以了)

 public class MyActivity extends Activity {
     ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

就是这么简单,然而现实是new Uri(“content://contacts”)报错了,Uri是个抽象类,不能这样实例化,然后我就像以前那样获取image那样处理

图片:
 Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, requestCode);
联系人:
Intent intent = new Intent(Intent.ACTION_PICK);
            intent.setType("content://contacts");
            startActivityForResult(intent,
                    GET_PHONENUM)

还是不行:No Activity found to handle Intent

然后找到网上一种通用的方法(很多人都这样写)

startActivityForResult(
new Intent(Intent.ACTION_PICK,
ContactsContract.Contacts.CONTENT_URI),
GET_PHONENUM);

在onActivityResult中回调

 // URI,每个ContentProvider定义一个唯一的公开的URI,用于指定到它的数据集
        Uri contactData = data.getData();
        // 查询就是输入URI等参数,其中URI是必须的,其他是可选的,如果系统能找到URI对应的ContentProvider将返回一个Cursor对象.
        Cursor cursor = managedQuery(contactData, null, null, null, null);
        cursor.moveToFirst();
        // 获得DATA表中的名字
        // username = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
        // 条件为联系人ID
        String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
        // 获得DATA表中的电话号码,条件为联系人ID,因为手机号码可能会有多个
        Cursor phone = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = "+ contactId, null, null);
        while (phone.moveToNext()) {
String usernumber = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            etPhone.setText(usernumber.replace(" ", ""));
        }
        if (!phone.isClosed()) {
            phone.close();
        }

通过CONTACT_ID和cursor语句去获取联系人信息(读写联系人的权限要先有)

然而我的小米手机却只读到了一部分联系人,而且只有最近联系人才能获取到手机号码,系统栏上面显示“请选择联系人”,而饿了么打开之后是显示“请选择电话号码”。
既然这样,那应该是我的发起请求的
ContactsContract.Contacts.CONTENT_URI
不太准确
Contacts下面有很多种URI
在http://www.cnblogs.com/renyuan/archive/2012/08/28/2660297.html( 还有很多uri的集合)
找到了

ContactsContract.CommonDataKinds.Phone.CONTENT_URI

发现用了这个之后可以打开选择电话号码的页面了,但是可能因为联系人和电话号码不是在同个数据库,结果cursor没有找到联系人的号码,也就不会执行
phone.moveToNext()后的代码了。

还有这里managedQuery这个方法过时了,用CursorLoader处理。

然后,我决定还是去看看饿了么是怎么处理的(本来想应该很快解决的,毕竟反编译也要时间),解压apk后用dex2jar反编译dex,解压后有3个,用luyten查看源码,混淆加密是必须的,然后我就用adb命令

adb shell dumpsys activity | grep "mFocusedActivity"

获取当前的Activity(获取当前Activity也有个APP叫“当前Activity”,插一句,我发现酷安有很多好玩的软件,很程序员)
找到对应的包

这里写图片描述

这里的TYPE就是ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE

然后回调,在aew类中的找到初始化的时候地址有setText,回调就没看到

ContactsContract.Contacts.CONTENT_URI无法获取手机号码_第1张图片

这里有的类aew$3,在这个dex没找到

在另外的dex找到了,这里的e就是地址

ContactsContract.Contacts.CONTENT_URI无法获取手机号码_第2张图片

完整代码

    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent intent) {
        super.onActivityResult(requestCode,resultCode,intent);
        if (requestCode == GET_PHONENUM) {
            if (resultCode == RESULT_OK) {
                final CursorLoader cursorLoader = new CursorLoader(this, intent.getData(), new String[] { "data1" }, null, null, null);
                cursorLoader.registerListener(1,new AddressCursorLoader());
                cursorLoader.startLoading();
            }
        }
    }
    public class AddressCursorLoader implements Loader.OnLoadCompleteListener<Cursor> {

        @Override
        public void onLoadComplete(Loader loader, Cursor cursor) {
            if (cursor == null) {
                return;
            }
            final int columnIndex = cursor.getColumnIndex("data1");
            if (cursor.moveToFirst()) {
                final String string = cursor.getString(columnIndex);
                if (StringUtil.isValid(string)) {
                  etPhone.setText(string.replace(" ",""));
                }
            }
            cursor.close();
        }

你可能感兴趣的:(android)