Painful problem
I always forgot to store my contacts on google or anywhere.
Sometimes I don't want to either.
When I changed my smartphone, I have to transfer my contacts essentially. Manually adding contacts is a huge pain.
Research I did
I've researched some applications but unfortunately didn't like their behaviour. They were not open source or they were using bluetooth. I didn't trust some of them either.
Solution
After some researchs, I've decided to code an android app. I've used expo with react native to build a quick solution for transfering contacts.
Basically, Your old phone can send your contacts in a json format.
On your new phone, you can use that json file to compare values and import them.
This is an open source app called contacto.
It might be helpful for react native beginners to read and understand, what contacto does in under the hood.
Quick Tips
contacto uses Contacts, Sharing, FileSystem, DocumentPicker, IntentLauncher as well for achieving for transfering contacts.
Every contact number on a phone can be imported with a file format called vcf. It stands for Variant Call Format.
Which I create vcf aka vCard with this function.
const getVcardTemplate = (name, number) =>`
BEGIN:VCARD
VERSION:2.1
N:;${name};;;
TEL;CELL:${number}
END:VCARD
`
Show me the code ...
We get phone contacts data with Contacts API with expo
We have to get permission first, to get contacts then we can iterate that data to get numbers and names.
I also get the id from contacts for rendering unique objects on the FlatList
getPhoneContacts = async () => {
const { status } = await Contacts.requestPermissionsAsync()
if (status === 'granted') {
// Getting contacts with permissions on android
const { data } = await Contacts.getContactsAsync({
fields: [
Contacts.PHONE_NUMBERS,
],
})
// Getting data we need.
const contacts = []
data.map((number) => {
const { name, phoneNumbers, id } = number
if (name && phoneNumbers && id) {
let phoneNumber = phoneNumbers[0]?.number
phoneNumber = phoneNumber.replace(/\s+/g, '')
contacts.push({ name, number: phoneNumber, id })
}
})
// Let's write phone contacts to a json file.
const jsonContacts = JSON.stringify(contacts)
const uri = createFileName(FileSystem, 'contacts.json')
await this.writeContactsToFile(uri, jsonContacts)
await this.sendOldPhoneContacts(uri)
}
}
Another key function for comparing values
We pick the contacts.json with DocumenPicker.
Get the permission and get new phone contacts too for comparing numbers.
Then, we have to iterate parsed contact.json and create vCard templates.
After aggregating data, we can simply write a new vcf file.
compareNumbers = async () => {
const result = await DocumentPicker.getDocumentAsync({})
if (result.type === 'success') {
if (!result.name.includes('contacts.json')) {
alert('You have to select contacts.json')
return
} else {
alert(`You've picked the file: ${result.name}`)
}
const { uri } = result
if (uri) {
try {
const jsonContacts = await FileSystem.readAsStringAsync(uri)
const parsedContacts = JSON.parse(jsonContacts)
const { status } = await Contacts.requestPermissionsAsync()
if (status === 'granted') {
// Getting contacts with permissions on android
const { data } = await Contacts.getContactsAsync({
fields: [
Contacts.PHONE_NUMBERS,
],
})
const numbers = []
data.map((number) => {
const { phoneNumbers } = number
if (phoneNumbers) {
let phoneNumber = phoneNumbers[0]?.number
phoneNumber = phoneNumber.replace(/\s+/g, '')
numbers.push(phoneNumber)
}
})
const newContacts = []
let vCardTotal = ''
parsedContacts.map((contact) => {
const { name, number, id } = contact
// Finding unrecorded phone numbers
const exist = numbers.find((currentNumber) => currentNumber === number)
if (!exist) {
newContacts.push({ id, name, number })
const vCard = getVcardTemplate(name, number)
vCardTotal += vCard
} else {
console.log(`${number} is exist !`)
}
})
const newRecordsUri = createFileName(FileSystem, 'new_contacts.vcf')
this.setState({ newContacts, newRecordsUri })
if (vCardTotal) {
await this.writeContactsToFile(newRecordsUri, vCardTotal)
} else {
alert('Your contacts are up to date !')
}
}
} catch (err) {
throw new Error(err)
}
}
} else {
alert('You have to give permission for comparing contacts !')
}
}
Importing VCF file for adding contacts with expo is not documented.
I had to use IntentLauncher for viewing vcf file. You cant import via Linking
importNewContacts = async () => {
const { newRecordsUri } = this.state
await FileSystem.getContentUriAsync(newRecordsUri).then((cUri) => {
IntentLauncher.startActivityAsync('android.intent.action.VIEW', {
data: cUri,
type: 'text/x-vcard',
flags: 1,
})
})
}
Anyways, I hope this would be helpful or resolves somenone's issue.
Top comments (0)