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 astoDeepLink
.
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
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.
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
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
iPhone Sdk Internet Connection Detection
How to Scale a Uibutton's Imageview
How to Send Multiple Parameterts to PHP Server in Http Post
Is Possible to Simulate Touch Event Using an External Keyboard on iOS Jailbroken
This Class Is Not Key Value Coding-Compliant for the Key Xxxxxx
Could Not Find Module for Target 'X86_64-Apple-Ios-Simulator'
How to Create Border in Uibutton
Missing Marketing Icon Xcode Bug
Playing Back Audio Using Avaudioplayer iOS 7
Xcode UI Testing Error Keyboard
Back Button Callback in Navigationcontroller in iOS
How to Add Older Version of iOS Sdk in Xcode 4.5
How to Get Managedobjectcontext for Viewcontroller Other Than Getting It from Appdelegate
Why Can't I Call the Default Super.Init() on Uiviewcontroller in Swift