Запуск приложения с пользовательской клавиатуры iOS8
Я хочу запустить мое содержащее приложение.
Я попытался использовать схемы URL.
Схема URL запустила приложение из других мест - так что проблемы там нет.
Похоже, что этот объект равен нулю:
self.extensionContext
поэтому я не могу запустить этот метод:
[self.extensionContext openURL:url completionHandler:nil];
Могу ли я запустить приложение? Утилиты URL-схемы работают на пользовательской клавиатуре?
спасибо!
Ответы
Ответ 1
Чтобы ответить на мой СОБСТВЕННЫЙ вопрос:
В пользовательской клавиатуре iOS8 объект extensionContext равен нулю, поэтому я не могу использовать его для запуска содержащего приложения.
Обходной путь, с которым я столкнулся, это:
- создать схему URL для вашего приложения.
- добавьте UIWebView в свой входной файл.
- загрузите схему URL-адресов для вашего приложения, содержащего веб-просмотр.
Я не уверен, что Apple допустит это, но теперь это работает.
Ответ 2
Попробуйте этот код
UIResponder* responder = self;
while ((responder = [responder nextResponder]) != nil)
{
NSLog(@"responder = %@", responder);
if([responder respondsToSelector:@selector(openURL:)] == YES)
{
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:urlString]];
}
}
Ответ 3
Вот рабочее решение (протестированное на iOS 9.2) для расширения клавиатуры. Эта категория добавляет специальный метод для доступа к скрытому объекту sharedApplication
, а затем вызывает на нем openURL:
.
(Конечно, тогда вы должны использовать метод openURL:
с вашей схемой приложений.)
// Usage:
// UIInputViewController.openURL(NSURL(string: "your-app-scheme://")!)
extension UIInputViewController {
func openURL(url: NSURL) -> Bool {
do {
let application = try self.sharedApplication()
return application.performSelector("openURL:", withObject: url) != nil
}
catch {
return false
}
}
func sharedApplication() throws -> UIApplication {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application
}
responder = responder?.nextResponder()
}
throw NSError(domain: "UIInputViewController+sharedApplication.swift", code: 1, userInfo: nil)
}
}
В последнее время я разработал несколько иной подход:
// Usage:
// UIApplication.🚀sharedApplication().🚀openURL(NSURL(string: "your-app-scheme://")!)
extension UIApplication {
public static func 🚀sharedApplication() -> UIApplication {
guard UIApplication.respondsToSelector("sharedApplication") else {
fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication` does not respond to selector `sharedApplication`.")
}
guard let unmanagedSharedApplication = UIApplication.performSelector("sharedApplication") else {
fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication.sharedApplication()` returned `nil`.")
}
guard let sharedApplication = unmanagedSharedApplication.takeUnretainedValue() as? UIApplication else {
fatalError("UIApplication.sharedKeyboardApplication(): `UIApplication.sharedApplication()` returned not `UIApplication` instance.")
}
return sharedApplication
}
public func 🚀openURL(url: NSURL) -> Bool {
return self.performSelector("openURL:", withObject: url) != nil
}
}
Ответ 4
Apple не разрешает расширениям приложений, отличным от расширений Today, для открытия содержащего приложения.
Из рекомендаций:
Сегодня виджет (и другой тип расширения приложения) может попросить систему открыть свое приложение, вызвав метод openURL: completeHandler: класс NSExtensionContext.
Вы можете проверить здесь
Ответ 5
Я попытался сделать выше решения для последних xcode 8.2 и swift 3.0.
К сожалению. Я не могу заставить его работать. Поэтому я нашел свое собственное решение, и он хорошо работает в swift 3.0, xcode 8.2
func openURL(_ url: URL) {
return
}
func openApp(_ urlstring:String) {
var responder: UIResponder? = self as UIResponder
let selector = #selector(openURL(_:))
while responder != nil {
if responder!.responds(to: selector) && responder != self {
responder!.perform(selector, with: URL(string: urlstring)!)
return
}
responder = responder?.next
}
}
// Usage
//call the method like below
//self.openApp(urlString)
//URL string need to included custom scheme.
//for example, if you created scheme name = customApp
//urlString will be "customApp://?[name]=[value]"
//self.openApp("customApp://?category=1")
Ответ 6
Согласно документации Apple https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/index.html, вы должны использовать NSExtensionContext следующим образом:
NSExtensionContext *ctx = [[NSExtensionContext alloc] init];
[ctx openURL:[NSURL URLWithString:@"myapp://"] completionHandler:^(BOOL success){return ;}];
Ответ 7
Вот что я нашел, чтобы открыть любой URL, используя то, что было описано выше:
UIWebView * webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
NSString *urlString = @"https://itunes.apple.com/us/app/watuu/id304697459";
NSString * content = [NSString stringWithFormat : @"<head><meta http-equiv='refresh' content='0; URL=%@'></head>", urlString];
[webView loadHTMLString:content baseURL:nil];
[self.view addSubview:webView];
[webView performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:2.0];
Обратите внимание, что в этом случае я запускаю этот вызов из UIInputViewController.
Этот метод также должен работать с использованием схемы URL из содержащего приложения
ПРИМЕЧАНИЕ. Начиная с iOS 8.3 Apple убил этот метод
Ответ 8
В расширении приложения (например, пользовательская клавиатура), которое было бы обработано через UIViewController.extensionContext
, но с iOS 8.1.2, поле nil
в следующем вызове Swift:
self.extensionContext?.openURL(appURL, completionHandler: nil)
// Does nothing because extensionContext is nil (iOS 8.1)
На самом деле, невозможно использовать Application.sharedApplication.openURL(...)
в расширении приложения, как указано в документации Apple.
Итак, начиная с 8.1.2, обходным путем является использование немого UIWebView
для перенаправления на содержащее приложение следующим образом:
let webView = UIWebView(frame: CGRectMake(0, 0, 0, 0));
let url = "MyKeyboard://";
let content = "<head><meta http-equiv='refresh' content='0; URL=\(url)'></head>";
webView.loadHTMLString(content, baseURL: nil);
self.view.addSubview(webView);
let delayInSeconds = 2.0
let startTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delayInSeconds * Double(NSEC_PER_SEC)))
dispatch_after(startTime, dispatch_get_main_queue()) { () -> Void in
webView.removeFromSuperview()
}
Где MyKeyboard://
должно быть определено соответственно как схема URL в содержащем приложении.
Пожалуйста, обратите внимание, что я еще не знаю, одобрено ли это Apple. Переадресация на приложения с пользовательских клавиатур может быть достаточно плохим для пользователей.
Ответ 9
Версия Swift 2.2, сродни ответу DongHyun Jang для Objective-C:
func webLink(urlString: String) {
let url = NSURL(string: urlString)
var responder: UIResponder? = self
while let r = responder {
if r.respondsToSelector("openURL:") {
r.performSelector("openURL:", withObject: url)
break;
}
responder = r.nextResponder()
}
}
Ответ 10
Я боролся с этим пару дней. Я не мог заставить UIWebView работать внутри пользовательской клавиатуры.
Исправить: поместить его внутри viewDidAppear: анимированный вместо viewDidLoad (в другой записке здесь должен остаться код для пользовательской высоты клавиатуры).
код:
- (void)viewDidAppear:(BOOL)animated {
UIWebView * webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
NSString * content = @"<a href='your_app_schema://your_params'>anchor</a>";
[webView loadHTMLString:content baseURL:nil];
[self.view addSubview:webView];
}
Ответ 11
В соответствии с рекомендациями Apple по расширению, теперь не рекомендуется открывать внешние приложения из расширения.
Для справки см. рекомендации по обзору Apple
Раздел 4.4.1
Они не должны:
- Включить маркетинг, рекламу или покупки в приложении;
- Запустить другие приложения, кроме настроек; или