Today App Extension Widget Tap to Open Containing App

Today App Extension Widget Tap To Open Containing App

EDIT: Ok, just a little correction here. I got it working with placing a button over the label just like suggested above and the following code:

- (IBAction) goToApp: (id)sender { 
NSURL *url = [NSURL URLWithString:@"floblog://"];
[self.extensionContext openURL:url completionHandler:nil];
}

I linked it to a "Touch Up Inside" event. However, this also causes the app to launch when the user scrolls the Today view.

=======================================

I ran into the same issue. However, it seems that there is no solution for now since the release notes for the first beta of iOS 8 mention:

Known Issues: openURL does not work from an extension.

So I guess we will at least have to wait until beta 2.

Open main app via today extension

Today extensions have access to an NSExtensionContext which allows you to open an app. In your extension controller:

let myAppUrl = NSURL(string: "myapp://some-context")!
extensionContext?.openURL(myAppUrl, completionHandler: { (success) in
if (!success) {
// let the user know it failed
}
})

The success parameter is provided because the system may not be able to open a particular URL (say you want to launch "twitter://" but the user does not have the Twitter app installed. If you're launching your own app, this shouldn't be an issue.

Open Safari from my Today Extension (widget) within my app

You could use @Giuseppe_Lanza solution and parse url that you receive from Today Extension Widget. However, I would show an example where your url have a static components and looking for a path such as https:/www.apple.com/homepod or https:/www.apple.com/iphone based on user's input in the textField:

1- URL Scheme: myAppName

2- Add this to open your app with widget

@IBAction func goButton(_ sender: Any) {
openApp(widgetText: "\(textBox.text!)")
}

func openApp(widgetText:String) {

let str = "myAppName://https://www.apple.com/\(widgetText)"
let url = URL(string: str)!
if textBox.hasText == true {

extensionContext?.open(url, completionHandler: { (success) in
if (!success) {
print("error: )
}
})
}
}

3- AppDelegate

Define a variable and pass received url to webViewController, will parse url there.

open var receivedUrl:URL?

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool{

receivedUrl = url
//You need to alter this navigation to match your app requirement so that you get a reference to your previous view..
window?.rootViewController?.performSegue(withIdentifier: "toDeepLink", sender: nil)
}

Make sure to make add an identifier for this segue under the attributes
inspector as toDeepLink.

4- WebView & parsing url
Now you can get the receivedUrl like this

    override func viewDidLoad() {
super.viewDidLoad()

let myAppDelegate = UIApplication.shared.delegate as! AppDelegate
print("receivedUrl \(myAppDelegate.receivedUrl!)")
//url Parsing & getting rid off urlScheme
let urlToLoad = URL(string: "\(myAppDelegate.receivedUrl!.host! + ":" + myAppDelegate.receivedUrl!.path)")!
print(urlToLoad)
let urlRequest = URLRequest(url: urlToLoad)
webView.load(urlRequest)
}

Else, you need to parse it in a proper way like dictionary to assign dynamic values to respective keys in your dictionary and hence to your url or append "?" to your urlToLoad just before you attempt to append url.query as I did in the webView controller.

Open Settings app from Today Extension/Widget?

this code should be work


guard let url = URL(string: UIApplicationOpenSettingsURLString) else {
return
}
extensionContext?.open(url, completionHandler: { (success) in
if !success {
var responder = self as UIResponder?

while (responder != nil){
let selectorOpenURL = NSSelectorFromString("openURL:")
if responder?.responds(to: selectorOpenURL) == true {
_ = responder?.perform(selectorOpenURL, with: url)
}
responder = responder?.next
}
}
})

however I'm not sure what "additional review" means
Sample Image

How to open Specific View controller on Widgets/ Today Extension click

According to your requirement, I have created a sample to get this working correctly.

1. First of all in TodayViewController interface, create 3 different UIButtons and give their tag values to uniquely identify them.
Sample Image

Here I have given tags as: 1, 2, 3 to First, Second and Third UIButton.

2. Next you need to write the code to open your Containing App from Today Extension. In TodayViewController create an @IBAction for and connect it to all three UIButtons.

@IBAction func openAppController(_ sender: UIButton)
{
if let url = URL(string: "open://\(sender.tag)")
{
self.extensionContext?.open(url, completionHandler: nil)
}
}

In the above code, tag will be added to the url scheme to identify which UIViewController needs to be opened on UIButton press. So the url will look something like: open://1

3. In the Containing App's URL Types need to make an entry for URL Scheme, i.e

Sample Image

As evident from the above screenshot, there is no need to make entry for each url that you want to open from your extensions. URLs having same url scheme have only a single entry.

4. When the containing app is opened from extension, you can get the handle in AppDelegate’s application(_ : url: sourceApplication: annotation: ) method. Here, you can handle which controller to open i.e.

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool
{
if url.scheme == "open"
{
switch url.host
{
case "1":
//Open First View Controller

case "2":
//Open Second View Controller

case "3":
//Open Third View Controller

default:
break
}
}
return true
}

url.scheme identifies the scheme of URL i.e. open and url.host identifies the host component in the URL which is currently set to the UIButton's tag value which you can use to uniquely identify which UIButton is pressed and what to de next accordingly.

For more on Today Extensions, you can refer to: https://hackernoon.com/app-extensions-and-today-extensions-widget-in-ios-10-e2d9fd9957a8

Let me know if you still face any issues regarding this.

Containing App crashes when opened from Today extension in swift 4

I solved my problem,by modifying the app delegate's method like this :

Actual Problem was : we had SWRevealViewController which has to be initiated before calling other view controller's

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
var mainViewController : MainViewController!
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)

let viewController = storyBoard.instantiateViewController(withIdentifier: "swRevealController") as! SWRevealViewController
mainViewController = storyBoard.instantiateViewController(withIdentifier: "mainView") as! MainViewController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()

viewController.setFront(mainViewController, animated: true)

if url.scheme == "open"
{
switch url.host
{
case "1"?:
mainViewController.isTaxi = true
break
case "2"?:
mainViewController.isPfp = true
break
case "3"?:
mainViewController.isDarbi = true
break
default:
break
}
}
return true
}

Check if app launched via today widget on iOS...?

You need to show a loader/empty value inside the vc , then using NSNotificationCenter from inside openURL to set needed value

OR

Set a suite shared user default between your app and the widget to know that and give it a value before the line that directs to the app , and check it's value inside viewDidLoad of the vc , then set it to nil



Related Topics



Leave a reply



Submit