Swift : Share image using UIActivityViewController - ios

I want to share QR image on tap of button using ActivityViewController.
Below is code that I’ve used :
#IBAction func btnShareQRCode_Clicked(sender: UIButton) {
self.shareQRCodeUsingActivityViewController(self.imageviewQRCode.image!)
}
func shareQRCodeUsingActivityViewController(imageParamater: UIImage) {
let activityItem: [UIImage] = [imageParamater as UIImage]
let objActivityViewController = UIActivityViewController(activityItems: activityItem as [UIImage], applicationActivities: nil)
objActivityViewController.excludedActivityTypes = [UIActivityTypeAirDrop, UIActivityTypeAddToReadingList]
// objActivityViewController.popoverPresentationController?.sourceView = sender
self.presentViewController(objActivityViewController, animated: true, completion: {
objActivityViewController.completionWithItemsHandler = { activity, success, items, error in
if !success { print("cancelled")
return
}
if activity == UIActivityTypeMail {
print("mail")
}
else if activity == UIActivityTypeMessage {
print("message")
}
else if activity == UIActivityTypeSaveToCameraRoll {
print("camera")
}
}
})
}
func completionHandler() {
}
The issue with this is that it is getting crashed on mail stating an error regarding MailComposer.
I want to know how and where these MailComposer function should be handled?

If you are running this on iOS Simulator, Mail component is likely to fail.
Apart from that, I don't think you need to cast your activity items list as UIImage. Simply put an array of objects as a activityItems array.

Related

Sharing an AVPlayerAsset with UIActivityViewController

I'd like to share an Audio file that I have loaded into a AVPlayerAsset. I was wondering if this is possible, or what the correct way of doing this would look like. Here is what my code looks like:
func shareTrack(track: Track) {
guard let file = track.playerItem else { return } // This is the AVPlayerAsset
let activityController = UIActivityViewController(activityItems: [file], applicationActivities: nil)
activityController.completionWithItemsHandler = { (nil, completed, _, error ) in
if completed {
print("Success")
} else {
print("Canceled")
}
}
DispatchQueue.main.async{
self.present(activityController, animated: true)
}
}
You are using the word "file" but the asset is not a file. It is an asset. Other programs aren't going to know anything about that. If you want to share something, share a file URL.

Skip Button doesn't work for google pre roll on iOS

On iOS app with GoogleInteractiveMediaAds integrated "Skip Ad" button doesn't work. Meanwhile manual call adsManager.skip() works perfectly. The button itself reacts to the tuches because it changes bounds and seems highlighted. Unfortunately, I haven't found anything according to handle tap manually, so maybe somebody has already been in this situation and could help with it.
guard
let adInformation = delegate?.latestAdInformation(), let url = adInformation.urlForIMA,
let adContainer = delegate?.videoAdDisplayContainerView()
else { return }
switch adInformation.adsType {
case .interstitials, .none:
self.play(ignoreAds: true)
return
case .prerolls, .all:
fallthrough
#unknown default:
break
}
let adDisplayContainer = IMAAdDisplayContainer(adContainer: adContainer, companionSlots: nil)
let request = IMAAdsRequest(
adTagUrl: url,
adDisplayContainer: adDisplayContainer,
contentPlayhead: contentPlayhead,
userContext: nil)
adsLoader.requestAds(with: request)
func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
// Grab the instance of the IMAAdsManager and set ourselves as the delegate
adsManager = adsLoadedData.adsManager
adsManager?.delegate = self
// Create ads rendering settings and tell the SDK to use the in-app browser.
let adsRenderingSettings = IMAAdsRenderingSettings()
if let vc = delegate?.adWebControllerPreferredOpenViewController() {
adsRenderingSettings.webOpenerPresentingController = vc
}
// Initialize the ads manager.
adsManager?.initialize(with: adsRenderingSettings)
}
func adsLoader(_ loader: IMAAdsLoader!, failedWith adErrorData: IMAAdLoadingErrorData!) {
self.play(ignoreAds: true)
}
func adsManager(_ adsManager: IMAAdsManager!, didReceive event: IMAAdEvent!) {
if event.type == IMAAdEventType.LOADED {
adsManager.start()
}
}
func adsManager(_ adsManager: IMAAdsManager!, didReceive error: IMAAdError!) {
self.play(ignoreAds: true)
}
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager!) {
self.pause(ignoreAds: true)
}
func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager!) {
self.play(ignoreAds: true)
}

ActivityViewController Sharing Image not showing for LinkedIn & WhatsApp

I Created and extension for sharing text along with Image.
Here is the extension class
extension UIViewController {
func shareScreen(shareText:String?,shareImage:UIImage?){
var objectsToShare = [AnyObject]()
if let shareTextObj = shareText{
objectsToShare.append(shareTextObj as AnyObject)
}
if let shareImageObj = shareImage{
objectsToShare.append(shareImageObj)
}
if shareText != nil || shareImage != nil{
let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
present(activityViewController, animated: true, completion: nil)
}else{
print("There is nothing to share")
}
}
}
share if its contains images only.
guard loadImage == nil else {
self.shareScreen(shareText: "AppName", shareImage: loadImage)
return
}
For Other share accessories link (Message,Email,Skype,Facebook) it worked.
When Try to share via (LinkedIn & WhatsApp) the image is not showing?
The above code which I tried, Can any one let me know is there any provision to share text along with Image including with linkedIn & WhatsApp.

open "Messages" app in my app

I'm trying to develop an app, that take a number from a variable then open in "Messages" app with (1500) in the field To: and the variable value in Text Messages field like this
I tried this answer how to open an URL in Swift3 and Swift: How to open a new app when uibutton is tapped but i didn't figure out the URL for Messages app
what should I use? Big thanks.
use this
if MFMessageComposeViewController.canSendText() == true{
let recipients:[String] = ["1500"]
var messageController = MFMessageComposeViewController()
//messageController.messageComposeDelegate = self // implement delegate if you want
messageController.recipients = recipients
messageController.body = "Your_text"
self.present(messageController, animated: true, completion: nil)
}
You need to import "MessageUI" to your class and use the below code.
func sendMessages() {
if MFMessageComposeViewController.canSendText() == true {
let recipients:[String] = ["9895249619"]
let messageController = MFMessageComposeViewController()
messageController.messageComposeDelegate = self
messageController.recipients = recipients
messageController.body = "Your_message_text"
self.present(messageController, animated: true, completion: nil)
} else {
//handle text messaging not available
}
}
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
controller.dismiss(animated: true, completion: nil)
}

UIActivityIndicatorView doesn't stop at the right time

I'm trying to share video from my app with UIActivityViewController.
So, the process looks like that:
User is tapping on Share button.
I have to prepare video for him with my function saveToShare().
I'm starting animation for my UIActivityIndicatorView and launching saveToShare().
I'm sending notification from saveToShare to my controller.
Observer in my controller is launching function shareVideo().
shareVideo() looks like that:
func videoIsReady() {
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
let videoName = "NewWatermarkedVideoNew2Share.mov"
let exportPath = NSTemporaryDirectory().appending(videoName)
let exportUrl = URL(fileURLWithPath: exportPath)
let urlData = NSData(contentsOf: exportUrl)
if ((urlData) != nil){
let videoLink = exportUrl
let objectsToShare = [videoLink]
let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityVC.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
activityVC.setValue("#myhashtag", forKey: "subject")
activityVC.excludedActivityTypes = [UIActivityType.airDrop, UIActivityType.addToReadingList, UIActivityType.assignToContact, UIActivityType.copyToPasteboard, UIActivityType.openInIBooks, UIActivityType.postToTencentWeibo, UIActivityType.postToVimeo, UIActivityType.postToWeibo, UIActivityType.print, UIActivityType.saveToCameraRoll, UIActivityType.postToFlickr, UIActivityType.postToTwitter, UIActivityType(rawValue: "com.apple.reminders.RemindersEditorExtension"), UIActivityType(rawValue: "com.apple.mobilenotes.SharingExtension"),UIActivityType(rawValue: "com.google.Drive.ShareExtension"), UIActivityType(rawValue: "com.apple.mobileslideshow.StreamShareService")]
self.present(activityVC, animated: true, completion: {
})
} else {
print("url is empty...")
}
}
It works, but my UIActivityIndicatorView is not hidden before share dialog and actually is working for several seconds after that dialog is shown.
What is wrong here?
P.S. So, it works if I put UIActivityIndicatorView in DispatchQueue.main.async so my problem is solved but I don't know why this problem was arisen in the first place.
To get it to disappear immediately, you'll want to call the code on the main queue synchronously. To avoid a dead lock (in case videoIsReady() is called from the main queue) use this little extension I've developed:
extension DispatchQueue {
class func safeUISync(execute workItem: DispatchWorkItem) {
if Thread.isMainThread { workItem.perform() }
else { DispatchQueue.main.sync(execute: workItem) }
}
class func safeUISync<T>(execute work: () throws -> T) rethrows -> T {
if Thread.isMainThread { return try work() }
else { return try DispatchQueue.main.sync(execute: work) }
}
}
Now you can call your code as follows:
func videoIsReady() {
DispatchQueue.safeUISync {
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
...
}
You must be calling your videoIsReady() function from a background thread. All UI calls must be made from the main thread or the results are undefined. A common result is for the UI changes to take a LOOONG time to appear. (Another common result is a crash.)

Resources