Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send SMS to specific phone number using UIActivityViewController

I am using UIActivityViewController to invite contacts to my app. I just need to share a specific text. It works properly with all the share options, however when I try to send SMS, I can't find an option to add the specific contact programmatically, since I already have the phonenumber of that contact.

My current code looks like this -

if(NSClassFromString(@"UIActivityViewController")) {
    NSString *message = @"Hi,\nCheckout My App, a new messenger.";

    UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:@[message] applicationActivities:nil];
                [self presentViewController:activityVC animated:YES completion:nil];
}

I tried subclassing UIActivityItemProvider, but it's basically allowing me to send different message to different providers, but I don't want that.

Is there any way to select a specific contact or provide a phone number to UIActivityViewController?

like image 601
noob Avatar asked Feb 01 '16 16:02

noob


1 Answers

I have created subclass of UIActivityViewController which is work properly in Swift and Objective-C:

import UIKit
import MessageUI

@objcMembers public class PhoneNumberActivityItem: NSObject {
    let phoneNumber: String

    init(phoneNumber: String) {
        self.phoneNumber = phoneNumber
    }
}

@objcMembers public class ExtendedActivityViewController: UIActivityViewController, MFMessageComposeViewControllerDelegate {

    public override init(activityItems: [Any], applicationActivities: [UIActivity]?) {
        let phoneNumberActivityItems = activityItems.filter({ $0 is PhoneNumberActivityItem }) as! [PhoneNumberActivityItem]

        guard MFMessageComposeViewController.canSendText(), !phoneNumberActivityItems.isEmpty else {
            super.init(activityItems: activityItems, applicationActivities: applicationActivities)
            return
        }

        var activities = [UIActivity]()
        let phoneNumbers: [String] = phoneNumberActivityItems.map { $0.phoneNumber }

        let extendedMessageActivity = ExtendedMessageActivity(phoneNumbers: phoneNumbers)
        activities.append(extendedMessageActivity)

        if let otherActivities = applicationActivities {
            activities.append(contentsOf: otherActivities)
        }

        super.init(activityItems: activityItems, applicationActivities: activities)

        extendedMessageActivity.messageComposeDelegate = self
        self.excludedActivityTypes = [.message]
    }

    public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
        controller.dismiss(animated: false, completion: nil)
    }

}

fileprivate extension UIActivity.ActivityType {
    static let extendedMessage = UIActivity.ActivityType("ExtendedMessage")
}

fileprivate class ExtendedMessageActivity: UIActivity {

    private let phoneNumbers: [String]
    private var message: String?

    weak var messageComposeDelegate: MFMessageComposeViewControllerDelegate?

    init(phoneNumbers: [String]) {
        self.phoneNumbers = phoneNumbers
        super.init()
    }

    override static var activityCategory: UIActivity.Category {
        return .share
    }

    override var activityType: UIActivity.ActivityType? {
        return .extendedMessage
    }

    override var activityTitle: String? {
        return NSLocalizedString("Message", comment: "")
    }

    override var activityImage: UIImage? {
        return UIImage(named: "message-app-icon")
    }

    override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
        for case is String in activityItems {
            return true
        }
        return false
    }

    override func prepare(withActivityItems activityItems: [Any]) {
        for case let text as String in activityItems {
            print(text)
            self.message = text
        }
    }

    override func perform() {
        let messageComposeVC = MFMessageComposeViewController()
        messageComposeVC.body = message
        messageComposeVC.recipients = phoneNumbers
        messageComposeVC.messageComposeDelegate = messageComposeDelegate
        UIApplication.getTopViewController()?.present(messageComposeVC, animated: true, completion: nil)
    }

}

fileprivate extension UIApplication {

    class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return getTopViewController(base: nav.visibleViewController)
        }
        else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
            return getTopViewController(base: selected)
        }
        else if let presented = base?.presentedViewController {
            return getTopViewController(base: presented)
        }
        return base
    }

}

Swift usage:

let activityItems: [Any] = ["Message Text", PhoneNumberActivityItem(phoneNumber: "+48 536 754 038")]
let extendedActivityVC = ExtendedActivityViewController(activityItems: activityItems, applicationActivities: nil)
extendedActivityVC.popoverPresentationController?.sourceView = self.view // to prevent iPad app crashes
self.present(extendedActivityVC, animated: true, completion: nil)

Objective-C usage:

NSArray *activityItems = [[NSArray alloc] initWithObjects:@"Some Message Text", [[PhoneNumberActivityItem alloc] initWithPhoneNumber:@"+48 123 456 789"], nil];
ExtendedActivityViewController *extendedActivityVC = [[ExtendedActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
extendedActivityVC.popoverPresentationController.sourceView = self.view; // to prevent iPad app crashes
[self presentViewController:extendedActivityVC animated:true completion:nil];

You will need "message-app-icon": 60x60 120x120 180x180

like image 113
zyxman Avatar answered Nov 14 '22 13:11

zyxman