Share image via WhatsApp - swift

I have in my app button to share image via whatsapp and it does work. But there is some strange thing appears in the menu of UIDocumentInteractionController on some devices.
This is the code:
let urlWhats = "whatsapp://app"
if let urlString = urlWhats.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed) {
if let whatsappURL = URL(string: urlString) {
if UIApplication.shared.canOpenURL(whatsappURL as URL) {
if let imageData = UIImageJPEGRepresentation(self.ivFramedPicture.image!, 1.0) {
let tempFile = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("/Documents/whatsAppTmp.wai")
do {
try imageData.write(to: tempFile, options: .atomic)
self.documentInteractionController = UIDocumentInteractionController(url: tempFile)
self.documentInteractionController.delegate = self
self.documentInteractionController.uti = "net.whatsapp.image"
self.documentInteractionController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true)
} catch {
print(error)
}
}
} else {
// Cannot open whatsapp
}
}
}
If I click on the 1 whatsapp icon it sends some file that doesn't open on iPhones (Android opens that file like image)
Does anyone can help to resolve that problem? I want only one icon with share image, that's it. Thanks

Simply use UIActivityController for sharing functionality instead of all that code.
Example:
if let image = self.ivFramedPicture.image
{
let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
}

Maybe try using the UIActivityViewController

Related

Is it possible to share image from App to Instagram Story

Now, I'm developing iOS, Android App. I wish to add a feature, easily sharing an image from my App to Instagram Story, directly. For example, tap button on my App, then transition to Instagram Story, and the user can share on Story.
I searched for some API, nothing to find a good way. Please tell me is possible to develop such a feature.
#IBAction func shareOnInstagram(_ sender: Any) {
DispatchQueue.main.async {
//Share To Instagram:
let instagramURL = URL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramURL!) {
let imageData = UIImageJPEGRepresentation(image, 100)
let writePath = (NSTemporaryDirectory() as NSString).appendingPathComponent("instagram.igo")
do {
try imageData?.write(to: URL(fileURLWithPath: writePath), options: .atomic)
} catch {
print(error)
}
let fileURL = URL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(url: fileURL)
self.documentController.delegate = self
self.documentController.uti = "com.instagram.exlusivegram"
if UIDevice.current.userInterfaceIdiom == .phone {
self.documentController.presentOpenInMenu(from: self.view.bounds, in: self.view, animated: true)
} else {
self.documentController.presentOpenInMenu(from: self.IGBarButton, animated: true)
}
} else {
print(" Instagram is not installed ")
}
}
}
You can use above code to share to Instagram and you need to set instagram in LSApplicationQueriesSchemes in project's info.plist
try this:-
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions) //.image to share image and .video to share video
if let lastAsset = fetchResult.firstObject {
let localIdentifier = lastAsset.localIdentifier
let u = "instagram://library?LocalIdentifier=" + localIdentifier
let url = NSURL(string: u)!
if UIApplication.shared.canOpenURL(url as URL) {
UIApplication.shared.open(URL(string: u)!, options: [:], completionHandler: nil)
} else {
let urlStr = "https://itunes.apple.com/in/app/instagram/id389801252?mt=8"
if #available(iOS 10.0, *) {
UIApplication.shared.open(URL(string: urlStr)!, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(URL(string: urlStr)!)
}
}
}

Why does my app crashes when I tap "Save Image" option on UIActivityViewController?

So, in the 3D Touch peek controller, I have this computed var where I setup the UIPreviewAction:
override lazy var previewActionItems: [UIPreviewActionItem] = {
let save = UIPreviewAction.init(title: "Share Image", style: UIPreviewAction.Style.default, handler: { (action, controller) in
let renderer = UIGraphicsImageRenderer(size: self.view.bounds.size)
let imageAux = renderer.image { ctx in
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true)
}
self.delegate!.shareImage(image: imageAux, url: self.data.url)
})
return [save]
}()
and in the delegate controller I have this method to present the UIActivityViewController:
func shareImage(image: UIImage, url: String) {
if let data = image.pngData() {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let filename = paths[0].appendingPathComponent(url)
try? data.write(to: filename)
}
let activityViewController = UIActivityViewController(activityItems: [image] , applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
self.present(activityViewController, animated: true, completion: nil)
}
everything works fine, i can share with any apps, and can store using the File Explore, but if I press "Save Image", the app crashes. Looks like I need gallery permission, but I don't know how to implement it in the UIPreviewAction to check if I have the permission or not, so that if I do it saves, and if I do not it asks for permission.
Add new records in your new InfoPlist.strings file.
<key>NSPhotoLibraryAddUsageDescription</key>
<string>$(PRODUCT_NAME)</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME)</string>
delete your app from simulator and run again.

How to open image in Instagram's sharing flow?

I'm trying to open an image in Instagram's sharing flow without having to download the image into the Photo Library. These two approaches work but they have downsides:
First Approach: This approach saves the image in a temporary location. It then uses UIDocumentInteractionController to open the image in Instagram's sharing flow. The problem here is that multiple apps are shown once the UIDocumentInteractionController is presented, I want to avoid this.
var documentController: UIDocumentInteractionController!
func shareToInstagram(image: UIImage) {
DispatchQueue.main.async {
let instagramURL = URL(string: "instagram://app")
if UIApplication.shared.canOpenURL(instagramURL!) {
let imageData = UIImageJPEGRepresentation(image, 100)
let writePath = (NSTemporaryDirectory() as NSString).appendingPathComponent("instagram.igo")
do {
try imageData?.write(to: URL(fileURLWithPath: writePath), options: .atomic)
} catch {
print(error)
}
let fileURL = URL(fileURLWithPath: writePath)
documentController = UIDocumentInteractionController(url: fileURL)
documentController.uti = "com.instagram.exlusivegram"
documentController.presentOpenInMenu(from: self.view.bounds, in: self.view, animated: true)
} else {
print(" Instagram is not installed ")
}
}
}
Second Approach: This is a nice approach because it does not use UIDocumentInteractionController, instead it immediately opens the image inside the Instagram sharing flow. The problem with this approach is that you must first save the image into the Photo Library, something I want to avoid.
func shareImage() {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
guard let lastAsset = fetchResult.firstObject else { return }
let localIdentifier = lastAsset.localIdentifier
let u = "instagram://library?LocalIdentifier=" + localIdentifier
let url = URL(string: u)!
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
print("Error")
}
}
I'm wondering if there is a way to use the second approach without having to save the image into the Photo Library? The first approach seems to save it into a temporary directory first, would it be possible to do this in the second approach?
Thank you

open PDF URL in iOS 8?

I have write this code to show pdf using UIDocumentInteractionController.But,I don't know how to search pdf at local directory and open in iOS 8 and below..Any help?
let filename = history.invoiceLongDate // 01223642
if !filename.isEmpty{
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let docs = paths[0]
let pathURL = NSURL(fileURLWithPath: docs, isDirectory: true)
if #available(iOS 9.0, *) {
let fileURL = NSURL(fileURLWithPath: "\(filename)_my_invoice.pdf", isDirectory: false, relativeToURL: pathURL)
self.docController = UIDocumentInteractionController(URL: fileURL)
self.docController?.delegate = self
self.docController?.presentOptionsMenuFromRect(sender.frame, inView: self.view, animated: true)
} else {
// Fallback on earlier versions
// Any Help with that?
}
}
You can view PDF in iOS 8 by using webview. Try below code,
if let pdf = NSBundle.mainBundle().URLForResource("myPDF", withExtension: "pdf", subdirectory: nil, localization: nil) {
let req = NSURLRequest(URL: pdf)
let webView = UIWebView(frame: CGRectMake(0,0,self.view.frame.size.width,self.view.frame.size.height))
webView.loadRequest(req)
self.view.addSubview(webView)
}
OR
if let baseUrl = NSURL.fileURLWithPath(pathURL) {
let fileURL = baseUrl.URLByAppendingPathComponent(NFConstants.NFCoreDataStringIdentifiers.CoreDataStoresPathComponent.rawValue)
}
Hope this will be helpful to you.
UIDocumentInteractionController is available with (iOS 3.2, *).
For Viewing PDF file:
var documentInteractionController: UIDocumentInteractionController!
#IBAction func openDocument(sender: UIButton) {
let URL: NSURL = NSBundle.mainBundle().URLForResource("pdf-sample", withExtension: "pdf")!
if (URL != "") {
// Initialize Document Interaction Controller
self.documentInteractionController = UIDocumentInteractionController(URL: URL)
// Configure Document Interaction Controller
self.documentInteractionController.delegate = self
// Present Open In Menu
self.documentInteractionController.presentOptionsMenuFromRect(sender.frame, inView: self.view, animated: true)
//presentOpenInMenuFromRect(button.frame, inView: self.view, animated: true)
}
}
// MARK: UIDocumentInteractionControllerDelegate
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController {
return self
}

Add Instagram to UIActivityViewController

I'm trying to share an image using standard UIActivityViewController, it's fine to share on Facebook, Twitter and Save Image using this code:
let firstActivityItem = "foo text"
let secondActivityItem : UIImage = image!
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem, secondActivityItem], applicationActivities: nil)
activityViewController.excludedActivityTypes = [
UIActivityTypePostToWeibo,
UIActivityTypePrint,
UIActivityTypeAssignToContact,
UIActivityTypeAddToReadingList,
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo
]
self.presentViewController(activityViewController, animated: true, completion: nil)
I need one more thing, Instagram:
If UIApplication.sharedApplication().canOpenURL(instagramURL!) {
// Success
var img = image!
var savePath: String = NSHomeDirectory().stringByAppendingPathComponent("Documents/Test.igo")
UIImageJPEGRepresentation(img, 1).writeToFile(savePath, atomically: true)
var imgURL = NSURL(string: NSString(format: "file://%#", savePath) as! String)
docController = UIDocumentInteractionController(URL: imgURL!) // 1
docController.UTI = "com.instagram.exclusivegram" // 2
docController.delegate = self
docController.annotation = ["InstagramCaption":"testsss"] // 3
docController.presentOpenInMenuFromRect(self.view.frame, inView: self.view, animated: true) // 4
} else {
// Error
}
Both these codes work fine separately, how can I add Instagram to the UIActivityViewController? Is it possible at all?
I think it would be very easier to add other social shares to the code you wrote for Instagram. The ".igo" extension is exclusive for Instagram so other apps will not support it. Just change this extension from ".igo" to ".ig" and other apps will read it:
var savePath: String = NSHomeDirectory().stringByAppendingPathComponent("Documents/Test.ig")
But Instagram also have an exclusive UTI to avoiding other apps to appear in the same Document Interaction View. So you will also need to change it from "exclusivegram" to "photo":
docController.UTI = "com.instagram.photo"
I have an app with a similar functionality and this is my original code:
#IBAction func shareOnIntagram(sender: UIButton) {
let finalImage: UIImage = UIImage.imageWithView(photoView)
let instagramURL = NSURL(string: "instagram://app")
if (UIApplication.sharedApplication().canOpenURL(instagramURL!)) {
let imageData = UIImageJPEGRepresentation(finalImage, 1)
let captionString = "caption"
let writePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("instagram.ig")
if imageData?.writeToFile(writePath, atomically: true) == false {
return
} else {
let fileURL = NSURL(fileURLWithPath: writePath)
self.documentController = UIDocumentInteractionController(URL: fileURL)
self.documentController.delegate = self
self.documentController.UTI = "com.instagram.photo"
self.documentController.annotation = NSDictionary(object: captionString, forKey: "InstagramCaption")
self.documentController.presentOpenInMenuFromRect(self.view.frame, inView: self.view, animated: true)
}
} else {
print(" Instagram is not installed ")
}
}
To make this code work, don't forget to add UIDocumentInteractionControllerDelegate in the UIViewController class.
It seems it's not possible, because of .igo extension which is needed by Instagram.