When I use UIActivityViewController to share an image the close button becomes transparent. I can click on its frame button but it is invisible for the user. And you cannot click outside to close on the sheet.
let activityItemMetadata = LinkMetadataManager(qrImage: image)
let activityVC = UIActivityViewController(
activityItems: [activityItemMetadata],
applicationActivities: nil)
activityVC.completionWithItemsHandler = {(activityType: UIActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) in
}
activityVC.activityItemsConfiguration = [
UIActivity.ActivityType.mail,
UIActivity.ActivityType.copyToPasteboard,
UIActivity.ActivityType.airDrop,
UIActivity.ActivityType.message
] as? UIActivityItemsConfigurationReading
activityVC.isModalInPresentation = false
self.present(activityVC, animated: true)
Close button appear like this:
Most of your UIActivityViewController code is wrong.
You should not be creating a LinkMetadataManager from the image and then using it as the item you wish to share.
You are trying to create an array of activities and setting those as the activity configuration. This is all wrong.
Your code should look more like the following:
let activityVC = UIActivityViewController(activityItems: [ image ], applicationActivities: nil)
activityVC.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
if completed || activityType == nil {
// activity view is being dismissed
}
}
present(activityVC, animated: true)
If you have a need to exclude certain activities you can add a line like the following:
activityVC.excludedActivityTypes = [ .assignToContact ] // Optionally exclude specific activities
If you want a bit more control you make use of UIActivityItemsConfiguration. The following is an example:
let configuration = UIActivityItemsConfiguration(objects: [ image ])
configuration.perItemMetadataProvider = { (index, key) in
switch key {
case .linkPresentationMetadata:
// Maybe make use of your LinkMetadataManager class here
var info = LPLinkMetadata()
info.title = "Some Title"
return info
default:
return nil
}
}
let activityVC = UIActivityViewController(activityItemsConfiguration: configuration)
activityVC.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
if completed || activityType == nil {
// activity view is being dismissed
}
}
present(activityVC, animated: true)
Related
I am using share sheet to open some of the native apps - i.e. Mail, Reminders, Notes, Messages. Below is my code to open share sheet after clicking on the share button.
I am looking for a way to identify a user click on share sheet i.e. an API that gets called when user selects an option on the share sheet. I searched and couldn't find anything, so not sure if there is a way to identify user selection?
func presentShareSheet(content: String, subject: String = "", shareButton: UIView? = nil, presentingVC: UIViewController? = nil) -> Guarantee<Void> {
return Guarantee { seal in
let itemsToShare: [Any] = [someItems]
let activityViewController = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = shareButton
activityViewController.completionWithItemsHandler = { activityType, completed, items, error in
// update color of navigation bar
seal(())
}
if let vc = presentingVC ?? UIApplication.shared.topMostViewController() {
vc.present(activityViewController, animated: true)
} else {
seal(())
}
}
}
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.
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.
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.)
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.