安卓端导出联系人为VCF文件方法及扩展字段设置方案
我来帮你解决这两个关于安卓联系人导出VCF的问题:
一、安卓系统自带导出所有联系人到VCF的方法
如果你不需要自定义导出字段,直接用系统自带功能最方便:
- 打开安卓设备上的「联系人」应用
- 点击右上角的菜单按钮(通常是三个垂直点)
- 在弹出的菜单中选择「导出/导入」选项(部分机型可能在「设置」子菜单里)
- 选择「导出到存储设备」,确认保存路径后,系统会自动生成包含所有联系人完整信息的VCF文件
二、修改代码补充缺失的VCF字段
你的现有代码已经实现了基础字段的导出,下面我会根据VCF 3.0规范,帮你添加图片、生日、亲属关系等缺失字段,同时处理空值避免报错:
首先,需要添加一个工具方法将联系人图片转成Base64(VCF的PHOTO字段要求二进制数据用Base64编码):
private String getBase64FromBitmap(Bitmap bitmap) { if (bitmap == null) return null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 90, baos); byte[] imageBytes = baos.toByteArray(); return Base64.encodeToString(imageBytes, Base64.DEFAULT); }
然后修改你的导出代码,补充所有缺失字段:
Person p = getPerson(); File vcfFile = new File(this.getExternalFilesDir(null), "generated.vcf"); FileWriter fw = new FileWriter(vcfFile); fw.write("BEGIN:VCARD\r\n"); fw.write("VERSION:3.0\r\n"); fw.write("N:" + p.getSurname() + ";" + p.getFirstName() + "\r\n"); fw.write("FN:" + p.getFirstName() + " " + p.getSurname() + "\r\n"); fw.write("ORG:" + p.getCompanyName() + "\r\n"); fw.write("TITLE:" + p.getTitle() + "\r\n"); fw.write("TEL;TYPE=WORK,VOICE:" + p.getWorkPhone() + "\r\n"); fw.write("TEL;TYPE=HOME,VOICE:" + p.getHomePhone() + "\r\n"); fw.write("ADR;TYPE=WORK:;;" + p.getStreet() + ";" + p.getCity() + ";" + p.getState() + ";" + p.getPostcode() + ";" + p.getCountry() + "\r\n"); fw.write("EMAIL;TYPE=PREF,INTERNET:" + p.getEmailAddress() + "\r\n"); // 1. 添加联系人图片(需确保Person类有获取头像Bitmap的方法,比如getAvatar()) String photoBase64 = getBase64FromBitmap(p.getAvatar()); if (photoBase64 != null) { fw.write("PHOTO;ENCODING=b;TYPE=JPEG:" + photoBase64 + "\r\n"); } // 2. 添加生日(需确保Person类有获取生日的方法,这里假设返回Date类型,转成YYYY-MM-DD格式) if (p.getBirthday() != null) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); String birthdayStr = sdf.format(p.getBirthday()); fw.write("BDAY:" + birthdayStr + "\r\n"); } // 3. 添加亲属关系(示例为父亲、配偶,可根据需求扩展其他亲属类型) if (p.getFatherName() != null && !p.getFatherName().isEmpty()) { fw.write("RELATED;TYPE=father:" + p.getFatherName() + "\r\n"); } if (p.getSpouseName() != null && !p.getSpouseName().isEmpty()) { fw.write("RELATED;TYPE=spouse:" + p.getSpouseName() + "\r\n"); } // 4. 添加助理信息(姓名用X-ASSISTANT,电话用TEL;TYPE=ASSISTANT) if (p.getAssistantName() != null && !p.getAssistantName().isEmpty()) { fw.write("X-ASSISTANT:" + p.getAssistantName() + "\r\n"); } if (p.getAssistantPhone() != null && !p.getAssistantPhone().isEmpty()) { fw.write("TEL;TYPE=ASSISTANT,VOICE:" + p.getAssistantPhone() + "\r\n"); } // 5. 添加备注(替换换行符避免破坏VCF格式) if (p.getNote() != null && !p.getNote().isEmpty()) { fw.write("NOTE:" + p.getNote().replace("\n", "\\n") + "\r\n"); } // 6. 添加标签(多个标签用逗号分隔) if (p.getCategories() != null && !p.getCategories().isEmpty()) { fw.write("CATEGORIES:" + String.join(",", p.getCategories()) + "\r\n"); } // 7. 添加网站信息 if (p.getWebsite() != null && !p.getWebsite().isEmpty()) { fw.write("URL;TYPE=WORK:" + p.getWebsite() + "\r\n"); } fw.write("END:VCARD\r\n"); fw.close(); Intent i = new Intent(); i.setAction(android.content.Intent.ACTION_VIEW); i.setDataAndType(Uri.fromFile(vcfFile), "text/x-vcard"); startActivity(i);
注意事项:
- 请确保你的
Person类对应有获取这些字段的方法(比如getAvatar()、getBirthday()等),如果字段名不同请自行调整 - VCF字段对格式要求严格,比如生日必须是
YYYY-MM-DD格式,备注里的换行符要替换成\n避免破坏VCF结构 - 自定义字段(比如
X-ASSISTANT)大部分通讯录应用都能识别,若需更标准的字段可参考VCF官方规范调整
内容的提问来源于stack exchange,提问作者Manoj Kumar




