iOS UIDocumentInteractionController LaunchServices: invalidationHandler called - ios

I'm having an issue when I try to Launch Instagram from my app. Everything works and I'm able to launch IG and even see the photo I sent etc.
The problem is that the UIDocumentInteractionController is crashing my app. And YES I have done my research.
I've seen the posts LIKE THIS that indicate that this is an Apple bug as as long as you can fix the crash, you should be able fine and ignore the Launch Services message.
The problem is I am still having the crash and trying to figure out how to resolve it.
I found a post that talks about adding an IF-STATEMENT after presenting the ViewController HERE, this post was written in Objective-C, and the example was not for a UIDocumentInteractionController.
I tried to take a stab at it in Swift, but it is still not working out for me. Would appreciate if someone can help out.
dic = UIDocumentInteractionController(URL: imageURL!)
dic.delegate = self
var annotationDictionary: [String: String] = ["InstagramCaption": "Test"]
dic.annotation = annotationDictionary
dic.UTI = "com.instagram.exclusivegram"
dic.presentOpenInMenuFromRect(CGRectMake(1, 1, 1, 1), inView: self.view, animated: true)
if dic.respondsToSelector("popoverPresentationController") {
Scripts.log("InstagramVC Did Respond to popoverPresentationController")
var popoverController: UIPopoverPresentationController = self.popoverPresentationController!
popoverPresentationController?.sourceView = self.view
}

The fix in my case was to declare the UIDocumentInteractionController variable as part of the viewcontroller's class instead of creating it in the same function where I set up the annotation and UTI and called .presentOpenInMenuFromRect
So near the top of my class outside of any functions I declared the variable:
var docController = UIDocumentInteractionController()
And then when I was ready to use it, I configured everything about the already existing UIDocumentInteractionController instead of creating one:
docController = UIDocumentInteractionController(URL: imageURL!)
docController.UTI = "com.instagram.exclusivegram"
docController.delegate = self
docController.annotation = ["InstagramCaption":"Text"]
docController.presentOpenInMenuFromRect(rect, inView: self.view, animated: true)
The app stopped crashing and Instagram now loads with the image/text assigned. 😃👍
I found the suggestion that led me to this fix here: https://stackoverflow.com/a/16057399/428981 and then adapted for Swift

It sounds like your instance of UIDocumentInteractionController is going out of scope. Try making it a property on the class or some other way to retain it.

I had the same problem: sending the picture to Instagram worked but instantaneously crashed my app. I think it has something to do with how the UIDocumentInteractionController is handled by the system once another app opens. If you try to send the picture via the embedded Facebook or Twitter frameworks that open a popover on top of your app, then no crash happens...
In any case the way I finally made it work is by NOT declaring my viewController as delegate, so:
// dic.delegate = self
The downside being that you can't use any of the delegate methods. In my case I wasn't using them anyway.

Related

Programmatically scroll pdf in UIDocumentInteractionController

I'm showing a pdf file inside a UIDocumentInteractionController, like this:
let docController = UIDocumentInteractionController(url: documentsURL)
let url = NSURL(string:"itms-books:");
if UIApplication.shared.canOpenURL(url! as URL) {
docController.delegate = self
docController.presentPreview(animated: true)
}
I need to automatically scroll to the last page when the controller is shown, is there a way to do that? I didn't find one. Thanks to anyone who will send help!
I am afraid there is not a straight forward solution for this, even the documentation says it's a UIViewController but Xcode shows it is inherited from NSObject.
I'd recommend either rendering the PDF on a WKWebView or a UIScrollView. This will give you a room to wiggle.

XCODE / IOS - Share audio file to whatsapp with a direct opening

I am trying to share an audio file from my ios app to whatsapp, but with a direct opening of whatsapp, and not an opening of the sharing menu with all the tiles.
Here is what i have now:
// Getting the original file
let fileName = #MY FILE NAME#
let filePath = Bundle.main.path(forResource: fileName, ofType: "mp3")!
let urlData = URL.init(fileURLWithPath: filePath)
let nsData = NSData(contentsOf: urlData)
if (nsData != nil){
// Creating the temporary file to share in the accessible ressources
let newFileName = "file.mp3"
let newFilePath = "\(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])/\(newFileName)"
nsData?.write(toFile: newFilePath, atomically: true)
let newUrlData = URL.init(fileURLWithPath: newFilePath)
// Sharing the file to whatsapp
// Possibility 1 (does not work yet)
// let documentController = UIDocumentInteractionController(url: newUrlData)
// documentController.uti = "net.whatsapp.audio"
// documentController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true)
// Possibility 2 (works only with the sharing menu)
let activityVC = UIActivityViewController(activityItems: [NSURL(fileURLWithPath: newFilePath)], applicationActivities: nil)
self.present(activityVC, animated: true, completion: nil)
}
As I do this, sharing an audio file to whatsapp works, but it first open the sharing menu, with the messenger tile, message tile, notes tile, ... (and it doesn't works for the messenger app). In the end I would like to be able to share on messenger AND whatsapp.
As explicated here in the whatsapp documentation, I want to open directly the whatsapp application when I try to share the file:
Alternatively, if you want to show only WhatsApp in the application list (instead of WhatsApp plus any other public/*-conforming apps) you can specify a file of one of aforementioned types saved with the extension that is exclusive to WhatsApp:
images - «.wai» which is of type net.whatsapp.image
videos - «.wam» which is of type net.whatsapp.movie
audio files - «.waa» which is of type net.whatsapp.audio
When triggered, WhatsApp will immediately present the user with the contact/group picker screen. The media will be automatically sent to a selected contact/group.
So I tried to change the line :
let newFileName = "file.mp3"
To one of these :
let newFileName = "file.mp3.waa"
let newFileName = "file.waa"
let newFileName = "file.waa.mp3"
But it still shows the same sharing menu (and can't read the audiofile if it ends with the .waa extension).
-> 1) Is it possible to do what I want to do ?
-> 2) If not, is there a way to share to messenger & whatsapp with the same code keeping one sharing menu
-> 3) If not, is there a way to reduce the sharing menu to only one tile depending on different calling event, so there is no confusing choosing of tiles
Thanks,
Antoine
Cf: XCODE / IOS - How to use exclusive extension to immediately present whatsapp (.wai, .waa, .wam)
FYI: As I went through a lot of tests with this, I couldn't find any solution yet.
Whatsapp recognize the file extension, but cannot even read it. Once shared, when you click on it, it's written ".whatsapp audio file", nothing more (And it's not even shared directly).
I sent a email to whatsapp developper team, they said they have others problem to fix currently, so it's not even on their to do list.
Wait & see..

How to post a video selected from the library on an apple device to a view controller in xcode using swift

I would like to choose a video from the library(which I have completed) NOW, I want to take that video and display it in a view controller. What do I do? I have looked everywhere and have found nothing.
Here is my code for trying to get the file name of a selected video from the library, which I am trying to display in a webview. It does not work.
videoURL = info[UIImagePickerControllerReferenceURL] as! NSURL?
let fileURL = NSURL(fileURLWithPath: " (videoURL)")
videoView.loadHTMLString( " ", baseURL : nil)
Any help is much appreciated. Thanks!
You'll need to implement the delegate methods.. Check this out:
How to select any Video or Movie file from UIImagePickerController

How share a screenshot to Facebook using Swift?

I need to have a Facebook share button on one of my app's view controllers so that when the user pushes it, it will share a screenshot of the user's current screen to Facebook.
I have been watching a few tutorials such as this one on how to implement a Facebook share button: https://www.youtube.com/watch?v=774_-cTjnVM
But these only show how I can share a message on Facebook, and I'm still a little bit confused how to share the whole screen that user is currently interacting with.
Sharing directly to Facebook isn't hard to do. First, import the Social framework:
import Social
Now add this as the action for your button:
let screen = UIScreen.mainScreen()
if let window = UIApplication.sharedApplication().keyWindow {
UIGraphicsBeginImageContextWithOptions(screen.bounds.size, false, 0);
window.drawViewHierarchyInRect(window.bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
let composeSheet = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
composeSheet.setInitialText("Hello, Facebook!")
composeSheet.addImage(image)
presentViewController(composeSheet, animated: true, completion: nil)
}
You might be interested to know that UIActivityViewController lets users share to Facebook but also other services. The code above is for your exact question: sharing to Facebook. This code renders the entire visible screen; you can also have individual views render themselves if you want.
Note: As Duncan C points out in a comment below, this rendering code won't include anything outside your app, such as other apps or system controls.
In iOS 8 and earlier there used to be a private framework that you could use to capture the entire screen. Using that framework would cause your app to be rejected for the app store, but at least it worked.
Starting in iOS 9 that API no longer works
The best you can do is to capture your app's views. That won't include the status bar or other things drawn by the system or other apps.
One way is to create an off-screen context, render the parent view you want to capture into the off-screen context (probably using drawViewHierarchyInRect:afterScreenUpdates:, load the data from the context into a UIImage, and then close the context.
Another way is a new API that will capture a snapshot of a view hierarchy. One of the new methods to capture a snapshot is snapshotViewAfterScreenUpdates. That creates specialized snapshot view.
swift 3
let screen = UIScreen.main
if let window = UIApplication.shared.keyWindow {
UIGraphicsBeginImageContextWithOptions(screen.bounds.size, false, 0);
window.drawHierarchy(in: window.bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
let composeSheet = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
composeSheet?.setInitialText("Hello, Facebook!")
composeSheet?.add(image)
present(composeSheet!, animated: true, completion: nil)
}

Game Center challenges is displaying instead of leaderboard in ios 8 app using swift

I am developing an ios 8 app using swift programming.
I am trying to display game center leaderboard using gamecentercontroller. But everytime it is displaying challenges state instead of leaderboard. Here is the code I have used.
func showLeaderboard()
{
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.leaderboardIdentifier = myLeaderboardIdentifier
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.gameCenterDelegate = self
let vc = self.view?.window?.rootViewController
vc?.presentViewController(gcViewController, animated: true, completion: nil)
}
When i try to use default state like
gcViewController.viewState = GKGameCenterViewControllerState.Dafault
Then it shows a blank white view (Not even challenges)
Just a wild doubt "does it have anything to do with sandbox mode)
Someone please help out. stuck on this for long.
It automatically started on my side when I wrote to Apple about it.
Seems like an issue from Apple's side.
Try using the following code. Remember to replace YourLeaderboardID with your actual leaderboard ID. Your code looks quite identical to mine, but probably the order of the lines of your code is wrong.
func showLeaderboard() {
var gcViewController: GKGameCenterViewController = GKGameCenterViewController()
gcViewController.gameCenterDelegate = self
gcViewController.viewState = GKGameCenterViewControllerState.Leaderboards
gcViewController.leaderboardIdentifier = "YourLeaderboardID"
self.showViewController(gcViewController, sender: self)
self.presentViewController(gcViewController, animated: true, completion: nil)
}
It just happened to me and I ended up here.
I don't know if it will be useful for someone but in my case the reason was that I got offline in airplane mode after getting authenticated.

Resources