需求:打开系统联系人,获取手机号码。
可能会遇到的问题:同一个用户多个手机号码
阅读本文会收获2个技能:
最开始我以为像类似获取系统图片那样去获取手机号码,很快解决,实际上也不是很难,方法对了就很快。
最开始根据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 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();
}