获取与 facebook for android 同步的联系人照片

Posted

技术标签:

【中文标题】获取与 facebook for android 同步的联系人照片【英文标题】:Get contacts photo which are synced with facebook for android 【发布时间】:2011-04-20 05:20:15 【问题描述】:

我试图在我的应用程序中显示联系人图片,但我得到的只是手动添加的图片,而不是与 facebook 同步的图片。如何解决这个问题?下面是我的代码:

Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Long.parseLong(PhotoId));
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
return BitmapFactory.decodeStream(input);

【问题讨论】:

我遇到了同样的问题。似乎仅与 FB 同步的联系人会出现此问题。对于从多个来源同步的联系人,即 twitter 和 FB,这很好。 【参考方案1】:

它不适用于仅从 FB 同步的联系人。您需要使用 FB graph API 并从那里获取照片;并且您需要知道联系人的 Facebook 名称。

 Bitmap contactPhoto = getImageBitmap("http://graph.facebook.com/mathiaslin/picture?type=square");

 final private static Bitmap getImageBitmap(String url) 
    Bitmap bm = null;
    try 
        URLConnection conn = new URL(url).openConnection();
        conn.connect();
        InputStream is = conn.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
        bm = BitmapFactory.decodeStream(bis);
        bis.close();
        is.close();
     catch (IOException e) 
        Log.e(TAG, "Error getting bitmap", e);
    
    return bm;

【讨论】:

为什么总是出错?当我连接到该 URL 时权限被拒绝? 您是否忘记将 INTERNET 权限添加到您的 androidManifest.xml 中?【参考方案2】:

在撰写本文时,我已尝试在 Stack Overflow 上找到的所有解决方案,但没有任何方法可以正确检索通过 Facebook 官方应用帐户同步适配器来自 Facebook 的照片。

需要明确的是,发布“认为”他们工作的解决方案的人可能使用 HTC sense 手机,该手机配备了由 HTC 编写的 Facebook 同步适配器,其安全要求与官方 Facebook 应用程序不同。

这是一个安全问题,其中一种方法确实设法尝试访问 facebook 照片的字节,您最终会得到一个 SqliteException ,说明请求的内容受到限制。

作为系统进程运行的相同代码会很好地提取照片。只是目前还不可能。

【讨论】:

【参考方案3】:

您提供的代码只能访问默认照片。此外,您应该将联系人 ID 附加到该 URI,而不是照片 ID(假设您使用数据表中的照片 ID)。

如果有多张照片,您可能想尝试直接从数据表中访问它们。您需要解析数据库游标并将原始字节数据手动转换为位图,如下所示:

String[] projection = ContactsContract.CommonDataKinds.Photo.PHOTO;
Uri uri = Uri. ContactsContract.Data.CONTENT_URI;
String where = ContactsContract.Data.MIMETYPE 
       + "=" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + " AND " 
       + ContactsContract.Data.CONTACT_ID + " = " + mContactId;
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);

if(cursor!=null&&cursor.moveToFirst())
    do
        byte[] photoData = photoCursor.getBlob(0);
        Bitmap photo = BitmapFactory.decodeByteArray(photoData, 0,
                photoData.length, null);

        //Do whatever with your photo here...
    while(cursor.moveToNext());

您希望 mContactId 与您要为其拍照的联系人对应。

如果您想仅限于 facebook 照片,则需要使用 ContactsContract.Data.RAW_CONTACT_ID 代替,您应该使用您的联系人 ID 和基于 facebook 帐户的过滤器从 RawContacts 表中获取它(假设您知道您要查找的帐户...可能因同步提供程序实施而异...)

【讨论】:

此方法仍会导致来自 facebook for android 的图片为空字节。我想这是因为 facebook for android 的 api 有一个白名单系统,它允许数据只共享给 android 默认应用程序。 我可以发誓,在使用类似方法之前我已经加载了 Facebook 照片……不过,这可能取决于您的同步提供商。我相信那里有几个不同的。您是否尝试过切换到不同的 Facebook 客户端应用程序? 是的,这正是问题所在。 facebook 的官方应用程序(facebook for android)似乎有一个愚蠢的政策,阻止其他应用程序使用数据。我很确定 Facebook 的另一个同步应用程序可以完成这项工作。【参考方案4】:

我得到了所有联系人的图片,甚至是从 facebook 同步的一些联系人的图片:

 * @param context
 *            The context used to retrieve the image.
 * @return The image of the user that is saved in the address book or null if
 *         the user does not exists or has no image.
 */
public Bitmap getContactPhoto(Context context) 
    ContentResolver contentResolver = context.getContentResolver();
    Uri photoUri = getCurrentUri(contentResolver);

    if (photoUri != null) 
        InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(
                contentResolver, photoUri);
        if (input != null) 
            return BitmapFactory.decodeStream(input);
        
     else 
        Log.d(getClass().getSimpleName(), "No photo Uri");
    
    return null;


private Uri getCurrentUri(ContentResolver contentResolver) 
    Cursor contact = contentResolver.query(lookUpUri,
            new String[]  ContactsContract.Contacts._ID , null, null, null);

    if (contact.moveToFirst()) 
        long userId = contact.getLong(contact.getColumnIndex(ContactsContract.Contacts._ID));
        return ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, userId);
    
    return null;

也许可以再次查看创建您的 photoId 的代码。不要使用数据表中照片的 Id 来创建 Uri。我也尝试过,只有当我使用直接链接到合并用户的 uri 时,检索照片才对我有用。然后,无论从何处同步,您都将获得此人的默认图像。

【讨论】:

这是否也适用于仅 FB 同步的联系人?我尝试过,但在尝试检索照片输入流后输入为 null 失败。 我看了看,它似乎只适用于一些 facebook 图片。看起来一些 Facebook 图片已复制到此人的 google 联系人中,然后我才能加载这些图片。【参考方案5】:

绝对没有办法以标准方式做到这一点。因此,我们必须使用 SQL 注入才能破解联系人数据库并获取 Facebook 头像。以下代码适用于大多数在 Android 2.2 或更高版本上使用 Motoblur 的摩托罗拉:

public static Bitmap loadFacebookAvatar(Context context, long personId) 
    String[] rawProjection = ContactsContract.RawContacts._ID;
    String contactIdAssertion = ContactsContract.RawContacts.CONTACT_ID + " = " + personId;
    String rawWhere = new StringBuilder()
            .append(contactIdAssertion).append(") UNION ALL SELECT ")
            .append(ContactsContract.RawContacts._ID).append(" FROM view_raw_contacts WHERE (")
            .append(contactIdAssertion).toString();
    Cursor query = context.getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI,
            rawProjection,
            rawWhere, null, null);
    if (query != null && query.moveToFirst()) 
        do 
            long id = query.getLong(query.getColumnIndex(ContactsContract.RawContacts._ID));
            String[] projection = ContactsContract.CommonDataKinds.Photo.PHOTO;
            Uri uri = ContactsContract.Data.CONTENT_URI;

            String mimeTypeAssertion = ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
            String photoAssertion = ContactsContract.CommonDataKinds.Photo.PHOTO + " IS NOT NULL";
            String rawContactIdAssertion = ContactsContract.CommonDataKinds.Photo.RAW_CONTACT_ID + " = " + id;

            String where = new StringBuilder().append(mimeTypeAssertion).append(" AND ")
                    .append(photoAssertion).append(" AND ").append(rawContactIdAssertion)
                    .append(") UNION ALL SELECT ").append(ContactsContract.CommonDataKinds.Photo.PHOTO)
                    .append(" FROM view_data WHERE (").append(photoAssertion).append(" AND ")
                    .append(rawContactIdAssertion).toString();

            Cursor photoQuery = context.getContentResolver().query(uri, projection, where, null, null);
            if (photoQuery != null && photoQuery.moveToFirst()) 
                do 
                    byte[] photoData = photoQuery.getBlob(photoQuery.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
                    if (photoData != null) 
                        return BitmapFactory.decodeByteArray(photoData, 0, photoData.length, null);
                    
                 while (photoQuery.moveToNext());
            
         while (query.moveToNext());
    
    return null;

对于其他手机,您必须获取联系人数据库并对其进行分析,以确定如何应用 SQL 注入,这需要有根手机。

【讨论】:

这似乎不再适用于 Android 4.0.x 设备。生成的 SQL 被转义以防止注入。 :(

以上是关于获取与 facebook for android 同步的联系人照片的主要内容,如果未能解决你的问题,请参考以下文章

Facebook SDK for Android 4.1.0 共享对话框取消

Android Facebook 与无效密钥哈希的集成

有没有办法知道用户使用 facebook SDK for Android 在 facebook 上有蓝色勾号?

朋友个人资料图片与 android 中 facebook 的个人资料名称不匹配

Facebook SDK Initialization for SDK v3.23.1 为 Android 实现应用事件

如何使用 FBSDK for iOS 获取 Facebook 好友列表?