Have you ever used Snapchat?
Yes?
Then you know it is one of the most popular Android apps on the Google Play Store right now.
However, have you ever thought how it went so viral and reached millions of users?
What secret strategy they have followed?
Any idea?
No?
Aside from its unique feature of sharing photos & videos with friends, “App Invite” feature played a huge role for making this to happen. “App Invite” feature allows app users to invite their friends to download the app.
And not only SnapChat, most of the other top apps like Instagram, Evernote, and Hike are also taking advantage of this feature.
Integrate “App Invite” in Your App
To add this feature, you’ll need to import contacts from iPhone to your iOS app.
Here, we’re going to share the step-by-step process on how to import contacts to iPhone to invite people via email and SMS.
Here’s the Real Juice
Create a new project under the file menu and select “Single View Application” and click on next button.
In the next tab, write a name of your app. Here, we’re naming it as “SOContactInvite”
Next, add two buttons to the first screen for navigating to the contact screen.
Once you add these two buttons, create “enum” as a type to show contact by category.
enum FetchType { case Email case PhoneNumber case BothPhoneAndEmail } Import “Address Book” in ContactListView.
After you import Address Book, define variable of ABAddressBookRef
lazy var addressBook: ABAddressBookRef = { var error: Unmanaged<CFError>? return ABAddressBookCreateWithOptions(nil, &error).takeRetainedValue() as ABAddressBookRef }()
Next, for the call, we’ll need the access of contact list as per the Apple’s privacy policy.
func SOGetPermissionContactAccess() { switch ABAddressBookGetAuthorizationStatus(){ case .Authorized: //Able to fetch authorize. Fetch contact list break case .Denied: //User not allowed to access contect list. break case .NotDetermined: if let theBook: ABAddressBookRef = addressBook{ ABAddressBookRequestAccessWithCompletion(theBook, {granted, error in if granted{ //Fetch contact list } else { } }) } case .Restricted: break } }
Once the user allows authentication call to fetch data from the contact list. It’s time we get records from the address book.
//MARK: GET RECORDS FROM ADDRESS BOOK func SOGetAddressBookRecord(type: FetchType) { let arrContactList = NSMutableArray() /* Get all the people in the address book */ let allPeople = ABAddressBookCopyArrayOfAllPeople( addressBook).takeRetainedValue() as NSArray for person: ABRecordRef in allPeople{ var dictPerson:Dictionary = [String:AnyObject]() var firstName: String = "" var lastName: String = "" let isFirstName: Bool = (ABRecordCopyValue(person, kABPersonFirstNameProperty) != nil) let isLastName: Bool = (ABRecordCopyValue(person, kABPersonLastNameProperty) != nil) if isFirstName { firstName = (ABRecordCopyValue(person, kABPersonFirstNameProperty).takeUnretainedValue() as? String)! dictPerson["first_name"] = firstName } if isLastName { lastName = (ABRecordCopyValue(person, kABPersonLastNameProperty).takeUnretainedValue() as? String)! dictPerson["last_name"] = lastName } var strFullName: String = "\(firstName) \(lastName)" strFullName = strFullName.stringByReplacingOccurrencesOfString("\"", withString: "") strFullName = strFullName.stringByReplacingOccurrencesOfString("''", withString: "'") dictPerson["contact_name"] = strFullName let recordId: Int = Int(ABRecordGetRecordID(person)) dictPerson["RecordID"] = recordId //For fetch image data if(ABPersonHasImageData(person)){ } else { } //For fetch contact list which contain email and phone both if type == FetchType.BothPhoneAndEmail { let emails: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue() if ABMultiValueGetCount(emails)>0 { var arrEmail = [AnyObject]() for counter in 0..<ABMultiValueGetCount(emails){ let email = ABMultiValueCopyValueAtIndex(emails, counter).takeRetainedValue() as! String arrEmail.append(email) } dictPerson["email"] = arrEmail } let phones: ABMultiValueRef = ABRecordCopyValue(person, kABPersonPhoneProperty).takeRetainedValue() if ABMultiValueGetCount(phones)>0 { var arrPhone = [AnyObject]() for counter in 0..<ABMultiValueGetCount(phones){ let phone = ABMultiValueCopyValueAtIndex(phones, counter).takeRetainedValue() as! String arrPhone.append(phone) } dictPerson["phone"] = arrPhone } if isFirstName == true || isLastName == true { arrContactList.addObject(dictPerson) } } else if type == FetchType.Email { //For fetch contact list which contain only email let emails: ABMultiValueRef = ABRecordCopyValue(person, kABPersonEmailProperty).takeRetainedValue() if ABMultiValueGetCount(emails)>0 { var arrEmail = [AnyObject]() for counter in 0..<ABMultiValueGetCount(emails){ let email = ABMultiValueCopyValueAtIndex(emails, counter).takeRetainedValue() as! String arrEmail.append(email) } dictPerson["email"] = arrEmail if isFirstName == true || isLastName == true { arrContactList.addObject(dictPerson) } } } else { //For fetch contact list which contain only Phone let phones: ABMultiValueRef = ABRecordCopyValue(person, kABPersonPhoneProperty).takeRetainedValue() if ABMultiValueGetCount(phones)>0 { var arrPhone = [AnyObject]() for counter in 0..<ABMultiValueGetCount(phones){ let phone = ABMultiValueCopyValueAtIndex(phones, counter).takeRetainedValue() as! String arrPhone.append(phone) } dictPerson["phone"] = arrPhone if isFirstName == true || isLastName == true { arrContactList.addObject(dictPerson) } } } } let descriptor: NSSortDescriptor = NSSortDescriptor(key:"contact_name", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:))) let sortedResults: NSArray = arrContactList.sortedArrayUsingDescriptors([descriptor]) } Next, to create a sectioned array to show in TableView, Declare… var arrSelectedContacts = NSMutableArray() var arrCharacters = NSMutableArray() var dictSections = [NSObject : AnyObject]() and call the method func initilizeTable(listArray: [AnyObject]) { let arrSectionData = NSMutableArray() arrCharacters = NSMutableArray() self.dictSections = [NSObject : AnyObject]() var strFirstLetter: String for dict in listArray { let strData: String = (dict["contact_name"] as! String) let index: String.Index = strData.startIndex.advancedBy(1) strFirstLetter = strData.substringToIndex(index).uppercaseString if ((dictSections[strFirstLetter]) == nil) { arrSectionData.removeAllObjects() arrCharacters.addObject("\(strFirstLetter)") } arrSectionData.addObject(dict) dictSections["\(strFirstLetter)"] = arrSectionData.copy() } print(dictSections) print(arrCharacters) //For reload the table view tblContacts!.reloadData() }
Once you declare a sectioned array, we’ll need to declare a mutable array as well, for keeping save selected contacts to send an invite.
var arrSelectedContacts = NSMutableArray()
For DataSource and Delegate method of UITableView when reloading the table.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return 54 } //MARK: UITableViewDataSource func numberOfSectionsInTableView(tableView: UITableView) -> Int { return arrCharacters.count } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let strLetter: String = arrCharacters[section] as! String let arrData: [AnyObject] = (dictSections[strLetter] as! [AnyObject]) return arrData.count } func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String { if arrCharacters.count == 0 { return "" } return arrCharacters[section] as! String } func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject] { let indexArray: [AnyObject] = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] return indexArray } func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int { var clickIndex: Int = 0 for strCharacter in arrCharacters { if (strCharacter as! String == title) { tblContacts!.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: clickIndex), atScrollPosition: .Top, animated: true) return clickIndex } clickIndex += 1 } return 0 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cell = tableView.dequeueReusableCellWithIdentifier("Cell") if cell == nil { cell = UITableViewCell(style: .Default, reuseIdentifier: nil) } let strIndexNames: String = arrCharacters[indexPath.section] as! String var arrIndexedCategories: [AnyObject] = (dictSections[strIndexNames] as! [AnyObject]) var dict: [String : AnyObject] = arrIndexedCategories[indexPath.row] as! [String : AnyObject] let label = UILabel(frame: CGRectMake(20, 10, 200, 21)) label.textAlignment = NSTextAlignment.Left label.text = dict["contact_name"] as? String cell!.contentView.addSubview(label) if contactType == .PhoneNumber { let arrPhone = dict["phone"] as! NSArray let strPhone = arrPhone[0] as! NSString if arrSelectedContacts.containsObject(strPhone) { cell?.accessoryType = UITableViewCellAccessoryType.Checkmark } else { cell?.accessoryType = UITableViewCellAccessoryType.None } } else { let arrEmail = dict["email"] as! NSArray let strEmail = arrEmail[0] as! NSString if arrSelectedContacts.containsObject(strEmail) { cell?.accessoryType = UITableViewCellAccessoryType.Checkmark } else { cell?.accessoryType = UITableViewCellAccessoryType.None } } return cell! }
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let strIndexNames: String = arrCharacters[indexPath.section] as! String var arrIndexedCategories: [AnyObject] = (dictSections[strIndexNames] as! [AnyObject]) var dict: [String : AnyObject] = arrIndexedCategories[indexPath.row] as! [String : AnyObject] if contactType == .PhoneNumber { let arrPhone = dict["phone"] as! NSArray let strPhone = arrPhone[0] as! NSString if arrSelectedContacts.containsObject(strPhone) { arrSelectedContacts.removeObject(strPhone) } else { arrSelectedContacts.addObject(strPhone) } } else { let arrEmail = dict["email"] as! NSArray let strEmail = arrEmail[0] as! NSString if arrSelectedContacts.containsObject(strEmail) { arrSelectedContacts.removeObject(strEmail) } else { arrSelectedContacts.addObject(strEmail) } } tblContacts?.reloadData() }
Once contact list is shown on screen you can select multiple contacts and can send email or message.
@IBAction func actionSend(sender: AnyObject) { if contactType == .PhoneNumber { presentModalMessageComposeViewController(true) } else { presentModalMailComposeViewController(true) } }
For Message Composer (For send message) you have import “MessageUI” and add
MFMessageComposeViewControllerDelegate, UINavigationControllerDelegate //MARK: MFMessageComposeViewController // 'import MessageUI' where you want to intigrate Message composer func presentModalMessageComposeViewController(animated: Bool) { if MFMessageComposeViewController.canSendText() { let arrRecipients = arrSelectedContacts as NSArray as! [String] let messageComposeVC = MFMessageComposeViewController() messageComposeVC.messageComposeDelegate = self messageComposeVC.body = “Invite Friends” messageComposeVC.recipients = arrRecipients presentViewController(messageComposeVC, animated: animated, completion: nil) } else { UIAlertView(title: NSLocalizedString("Error", value: "Error", comment: ""), message: NSLocalizedString("Your device doesn't support messaging", value: "Your device doesn't support messaging", comment: ""), delegate: nil, cancelButtonTitle: NSLocalizedString("OK", value: "OK", comment: "")).show() } } //MARK: MFMessageComposeViewControllerDelegate func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) { dismissViewControllerAnimated(true, completion: nil) }
For Mail Composer (For send Email) you have import “MessageUI” and add
MFMailComposeViewControllerDelegate, UINavigationControllerDelegate //MARK: MFMailComposeViewController // 'import MessageUI' where you want to use mail composer sheet func presentModalMailComposeViewController(animated: Bool) { if MFMailComposeViewController.canSendMail() { let arrRecipients = arrSelectedContacts as NSArray as! [String] let mailComposeVC = MFMailComposeViewController() mailComposeVC.delegate = self mailComposeVC.setSubject("Invite Friends") mailComposeVC.setMessageBody("Sending Friend Request", isHTML: true) mailComposeVC.setToRecipients(arrRecipients) presentViewController(mailComposeVC, animated: animated, completion: nil) } else { UIAlertView(title: NSLocalizedString("Error", value: "Error", comment: ""), message: NSLocalizedString("Your device doesn't support Mail messaging", value: "Your device doesn't support Mail messaging", comment: ""), delegate: nil, cancelButtonTitle: NSLocalizedString("OK", value: "OK", comment: "")).show() } } //MARK: MFMailComposeViewControllerDelegate func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) { if error != nil { print("Error: \(error)") } dismissViewControllerAnimated(true, completion: nil) }
This is how you can pull contacts from iPhone and send an invitation to your iPhone contacts either by email or SMS.
By adding this feature, you can increase the app downloads easily because if your present app users like using your app then they’ll definitely want to share it with their friends.
We’ve also integrated this feature into many of our projects which helped our clients to increase their app downloads.
We at Space-O Technologies have helped more than 25 startups to make their idea come to reality. And, If you’ve any app idea and looking for iPhone app development company, you can contact us to briefly discuss your idea so that we can help you achieve your end goal.
You can get the source code of this demo from GitHub here.
This page was last edited on January 11th, 2021, at 7:01.