How to disable contact section ( message , call , video , mail ) from CNContactPickerViewController - ios

I want to know it possible to remove or disable menu in that section.
Thank you.
extension ViewController: CNContactPickerDelegate {
#IBAction func pickerBtnAction(_ sender: Any) {
let contacVC = CNContactPickerViewController()
contacVC.displayedPropertyKeys = [CNContactPostalAddressesKey]
contacVC.hidesBottomBarWhenPushed = true
contacVC.displayedPropertyKeys = [CNContactGivenNameKey, CNContactImageDataAvailableKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactThumbnailImageDataKey, CNContactIdentifierKey];
contacVC.delegate = self
self.present(contacVC, animated: true, completion: nil)
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
if let phone = contactProperty.value as? CNPhoneNumber {
print(phone.stringValue)
}
}
}

let cncontactVC = CNContactViewController()
cncontactVC.allowsActions = false

You need to use instance property allowsActions of CNContactViewController.
From the official docs,
Determines whether to display buttons for actions such as sending a
text message or initiating a FaceTime call.
while creating an object of CNContactViewController,
let contactVC = CNContactViewController()
contactVC.allowsActions = false
There are other useful properties as well ,
shouldShowLinkedContacts
allowsEditing

Related

Sending SMS from Contacts for Multiple Contacts Fails

Im trying to acheive the same results as: Sending SMS from Contacts Fails
Sending an SMS or "App Invite" to contact(s).
The solution to this problem works, but it only allows you to send an SMS to one person at a time. What I want to do is send an SMS to multiple contacts at one time. Forgive me if this is fairly easy. I've been up for the past 14 hours programming and most things aren't making sense to me right now.
Heres my code:
//MARK : VARIABLES
let contactPickerViewController = CNContactPickerViewController()
let messageViewController = MFMessageComposeViewController()
//MARK : VIEW DID LOAD
override func viewDidLoad() {
super.viewDidLoad()
//-- set delegates equal to self
contactPickerViewController.delegate = self
messageViewController.messageComposeDelegate = self
}
//MARK : MFMESSAGECOMPOSE & CNCONTACTPICKERDELEGATE
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
self.dismiss(animated: true, completion: nil)
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
//-- select contacts and present message compose view controller
contacts.forEach { (contact) in
for data in contact.phoneNumbers {
let phoneNo = data.value
//-- configure message view controller
messageViewController.recipients = [phoneNo]
messageViewController.body = "Testing Testing"
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.present(self.messageViewController, animated: true, completion: nil)
})
}
}
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
print("cancelled")
}
In your for loop you are attempting to display an MFMessageComposeViewController for each recipient. This won't work as it will attempt to present multiple view controllers concurrently.
You can present a single MFMessageComposeViewController that has all of the recipients specified:
var recipients = [String]()
contacts.forEach { (contact) in
for data in contact.phoneNumbers {
let phoneNo = data.value
recipients.append(phoneNo.stringValue)
}
}
//-- configure message view controller
messageViewController.recipients = recipients
messageViewController.body = "Testing Testing"
self.present(self.messageViewController, animated: true, completion: nil)

Getting people name and number from mobile contact in IOS

I want exactly this process in my app https://www.youtube.com/watch?v=HKCXwm7r838. But the code in this tutorial is for older IOS version, i'm using IOS 10, Xcode 8.2, Swift 3.0, So its not working for me. I tried the following code to display the contact list. It works.
import UIKit
import ContactsUI
class ViewController: UIViewController, CNContactPickerDelegate{
#IBOutlet weak var textLabel: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func addExistingContact()
{
}
func contactPicker(picker: CNContactPickerViewController, didSelectContact contacts: CNContact)
{
// print(contacts.givenName)
}
#IBAction func button(_ sender: Any)
{
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
contactPicker.displayedPropertyKeys =
[CNContactGivenNameKey
, CNContactPhoneNumbersKey]
self.present(contactPicker, animated: true, completion: nil)
}
func contactPickerDidCancel(picker: CNContactPickerViewController)
{
print("Cancel Contact Picker")
}
}
Now, what I want is, when I select any contact name from the list, the contact list must disappear immediately, and then the selected name and number must be displayed in two labels/textFields in a viewController. Can someone tell me what code should i use ? Thanks in advance.
Replace methods contactPicker(picker: CNContactPickerViewController, didSelectContact contacts: CNContact) and contactPickerDidCancel(picker: CNContactPickerViewController) with
func contactPicker(_ picker: CNContactPickerViewController,
didSelect contactProperty: CNContactProperty) {
}
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
// You can fetch selected name and number in the following way
// user name
let userName:String = contact.givenName
// user phone number
let userPhoneNumbers:[CNLabeledValue<CNPhoneNumber>] = contact.phoneNumbers
let firstPhoneNumber:CNPhoneNumber = userPhoneNumbers[0].value
// user phone number string
let primaryPhoneNumberStr:String = firstPhoneNumber.stringValue
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
}
Given that your requirement is for the ContactPicker to close immediately after clicking on contact, you shouldn't implement the following methods. Remove the below given methods from your code.
func contactPicker(_ picker: CNContactPickerViewController, didSelect contacts: [CNContact]) {
}
func contactPicker(_ picker: CNContactPickerViewController, didSelectContactProperties contactProperties: [CNContactProperty]) {
}
I will tell you how to get your contact list. The last part of your post (The list stuff) you will have to do it yourself, as it's just playing around with TableView controllers.
First import:
import Contacts
I use this, for example, to get all my contacts:
let store = CNContactStore()
var contacts = [CNContact]()
let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactSocialProfilesKey] as [Any]
let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
do{
try store.enumerateContacts(with: request){
(contact, stop) in
contacts.append(contact)
}
guard contacts.count > 0 else{
//Show contact list
return
}
} catch let err{
print(err)
}
Also, somewhere in your code, you will want to ask for Contact Permission:
switch CNContactStore.authorizationStatus(for: .contacts){
case .authorized:
//
case .notDetermined:
store.requestAccess(for: .contacts){succeeded, err in
guard err == nil && succeeded else{
return
}
}
case .denied:
//
case .restricted:
//
default:
print("Not handled")
}
IMPORTANT: Add in your info.plist:
Privacy - Contacts Usage Description

iOS Swift CNContactPickerViewController search contact and add to selection

I am using iOS 9 and Swift 2.2
I have implemented iOS inbuilt CNContactPickerViewController using CNContactPickerDelegate to get the contact numbers,
In the CNContactPickerViewController Screen, when I click on search field on top and search for a name, I need to add that name to my selection but nothing happens after tapping the contact.
I searched everywhere and dint find any solution to this
Do I need to add anything to my code or is it a iOS 9 bug
#IBAction func AddBtnKlkFnc(sender: AnyObject)
{
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
contactPicker.displayedPropertyKeys =
[CNContactPhoneNumbersKey]
self.presentViewController(contactPicker, animated: true, completion: nil)
}
func contactPicker(picker: CNContactPickerViewController, didSelectContacts ContctAryVar: [CNContact])
{
for ContctVar in ContctAryVar
{
let ContctDtlVar = ContctDtlCls()
ContctDtlVar.ManNamVar = CNContactFormatter.stringFromContact(ContctVar, style: .FullName)!
for ContctNumVar: CNLabeledValue in ContctVar.phoneNumbers
{
var MobNumVar = ((ContctNumVar.value as! CNPhoneNumber).valueForKey("digits") as? String)!
if(MobNumVar.Len() > 10)
{
MobNumVar = MobNumVar.GetLstSubSrgFnc(10)
}
ContctDtlVar.MobNumVar = MobNumVar
ContctDtlAryVar.append(ContctDtlVar)
}
}
}
The search results seem to be working in single selection mode only, so make sure you implement
func contactPicker(CNContactPickerViewController, didSelect: CNContact)
only, but not
func contactPicker(CNContactPickerViewController, didSelect: [CNContact])
If you implement both, the version wich takes only one CNContact as argument is ignored and the multi selection mode is used instead.
Use this updated code and
#IBAction func AddBtnKlkFnc(sender: AnyObject)
{
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
contactPicker.displayedPropertyKeys =
[CNContactPhoneNumbersKey]
self.presentViewController(contactPicker, animated: true, completion: nil)
}
func contactPicker(picker: CNContactPickerViewController, didSelectContacts ContctAryVar: [CNContact])
{
for ContctVar in ContctAryVar
{
let ContctDtlVar = ContctDtlCls()
ContctDtlVar.ManNamVar = CNContactFormatter.stringFromContact(ContctVar, style: .FullName)!
for ContctNumVar: CNLabeledValue in ContctVar.phoneNumbers
{
var MobNumVar = ((ContctNumVar.value as! CNPhoneNumber).valueForKey("digits") as? String)!
if(MobNumVar.Len() > 10)
{
MobNumVar = MobNumVar.GetLstSubSrgFnc(10)
}
ContctDtlVar.MobNumVar = MobNumVar
ContctDtlAryVar.append(ContctDtlVar)
}
}
delegate.didFetchContacts([contact])
navigationController?.popViewControllerAnimated(true)
}
Here is a swift 4 version
#IBAction func addPhoneContact(_ sender: UIButton) {
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
contactPicker.displayedPropertyKeys =
[CNContactPhoneNumbersKey]
self.present(contactPicker, animated: true, completion: nil)
}
extension ViewController: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
picker.dismiss(animated: true, completion: nil)
let name = CNContactFormatter.string(from: contact, style: .fullName)
for number in contact.phoneNumbers {
let mobile = number.value.value(forKey: "digits") as? String
if (mobile?.count)! > 7 {
// your code goes here
}
}
}
}
Multi selection and search are mutually exclusive. If you want search to be working you have to go with single selection only and implement only single selection delegate method.

Sending SMS from Contacts Fails

I am implementing a seemingly trivial and very popular use case where users select a contact, and send them a precomposed SMS.
However, the SMS ViewController dismisses itself automatically. This is easily reproducible.
How do I fix this?
Here's my code:
import UIKit
import MessageUI
import ContactsUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate, CNContactPickerDelegate{
let contactPickerViewController = CNContactPickerViewController()
let messageVC = MFMessageComposeViewController()
override func viewDidLoad() {
super.viewDidLoad()
contactPickerViewController.delegate = self
messageVC.messageComposeDelegate = self
}
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
picker.presentViewController(messageVC, animated: true, completion: nil)
}
}
}
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
self.dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func invite(sender: AnyObject) {
self.presentViewController(self.contactPickerViewController, animated: true, completion: nil)
}
}
The problem is that you are asking your picker to present the message view controller. When contactPicker:picker:didSelectContact: method is called, the picker view controller is automatically being dismissed by the system. This means that the view controller is going away and you are trying to use that view controller to present your next view controller.
What you need to do is have "ViewController" in this case present the message view controller. Below is an example of the portion of your code i changed. You'll notice i have a timer there. This is because if you try to present the messageVC right away, nothing will happen because the contacts view controller isn't done dismissing itself yet.
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) {
if let phoneNumberValue = contact.phoneNumbers.first?.value as? CNPhoneNumber {
if let phoneNumber = phoneNumberValue.valueForKey("digits") as? String {
// Configure message ViewController
messageVC.recipients = [phoneNumber]
messageVC.body = "Yoyoyo"
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.presentViewController(self.messageVC, animated: true, completion: nil)
})
}
}
}

How to interpret MPMediaItemCollection codes

When I choose to print out MPMediaItemCollection in my app I simply receive codes such as 0x17eb5d30. Is anybody aware of how to get data from these random letters and numbers. I am looking at hopefully retrieving the title of the song as well as the length of the song in seconds.
My code is here
#IBAction func pickSong(sender: AnyObject) {
self.presentPicker(sender)
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestView: playMusicViewController = segue.destinationViewController as! playMusicViewController
DestView.selectedSong = MPMediaItemCollection()
}
}
func presentPicker (sender:AnyObject) {
let mediaPicker = MPMediaPickerController(mediaTypes: .Music)
mediaPicker.delegate = self
mediaPicker.allowsPickingMultipleItems = false
presentViewController(mediaPicker, animated: true, completion: {})
}
also the extension view controller
extension ViewController : MPMediaPickerControllerDelegate {
// must implement these, as there is no automatic dismissal
func mediaPicker(mediaPicker: MPMediaPickerController!, didPickMediaItems mediaItemCollection: MPMediaItemCollection!) {
let player = MPMusicPlayerController.applicationMusicPlayer()
player.setQueueWithItemCollection(mediaItemCollection)
player.play()
println(mediaItemCollection)
self.dismissViewControllerAnimated(true, completion: nil)
}
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController!) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
The number and letter you are seem is a pointer to an address in memory (normally not very useful for us) if you want to access details about the music you need to access the properties of the objects you received back for the picker. The example below show how to retrieve the title of the music selected:
func mediaPicker(mediaPicker: MPMediaPickerController!, didPickMediaItems mediaItemCollection: MPMediaItemCollection!) {
let player = MPMusicPlayerController.applicationMusicPlayer()
player.setQueueWithItemCollection(mediaItemCollection)
player.play()
let item = mediaItemCollection.representativeItem
let title = item.title
println(title)
self.dismissViewControllerAnimated(true, completion: nil)
}
I hope that help you!

Resources