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,回调就没看到

这里写图片描述

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

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

这里写图片描述

完整代码

    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<Cursor> 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();
        }
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
请参考以下代码: ```java import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class ContactActivity extends Activity { private ListView contactsListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contact); contactsListView = findViewById(R.id.contacts_list_view); String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME }; Cursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, null, null, null); String[] fromColumns = new String[] { ContactsContract.Contacts.DISPLAY_NAME }; int[] toViews = new int[] { android.R.id.text1 }; SimpleCursorAdapter adapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_1, cursor, fromColumns, toViews, 0); contactsListView.setAdapter(adapter); } } ``` 上述代码实现了读取系统联系人的姓名,并将其显示在界面中。要同时显示联系人的电话,我们需要在查询Contacts表时获取联系人的id,并在查询Data表时根据联系人id获取相应的电话信息。代码如下: ```java import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.widget.ListView; import android.widget.SimpleCursorAdapter; public class ContactActivity extends Activity { private ListView contactsListView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_contact); contactsListView = findViewById(R.id.contacts_list_view); String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME }; Cursor cursor = getContentResolver().query( ContactsContract.Contacts.CONTENT_URI, projection, null, null, null); String[] fromColumns = new String[] { ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER }; int[] toViews = new int[] { android.R.id.text1, android.R.id.text2 }; SimpleCursorAdapter adapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_2, cursor, fromColumns, toViews, 0); adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() { @Override public boolean setViewValue(android.view.View view, Cursor cursor, int columnIndex) { if (columnIndex == cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) { String phoneNumber = cursor.getString(columnIndex); ((android.widget.TextView) view).setText(phoneNumber); return true; } return false; } }); contactsListView.setAdapter(adapter); } } ``` 上述代码中,我们使用了SimpleCursorAdapter来将数据显示在ListView中。同时,我们还实现了ViewBinder接口,用于在显示电话信息时将其绑定到正确的TextView上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值