Tutorial: Transfering contacts with React Native
Tags: reactnative, javascript, android, contacts
Published: 2020-12-21 21:56:35

---
title: Tutorial: Transfering contacts with React Native
published: true
tags: reactnative, javascript, android, contacts
description: An android app for transfering contacts 
---
# 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.

![pain](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSdnTNMNAErCgTRu07hCMTk521lXak4MdocEQ&usqp=CAU)

# 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**.
> https://github.com/kaansan/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.