Je souhaite créer une fonctionnalité de partage de style Android pour mon application. J'ai créé une extension de partage qui est appelée lorsque vous sélectionnez des images dans l'application photo et que vous appuyez sur Partager. Maintenant, je veux que ces images soient envoyées à l'application principale et traitées ici. .____.] Ma question est la suivante:
Actuellement, il n'y a aucun moyen de le faire. Une extension de partage ne peut pas ouvrir l'application contenant.
L'approche prévue pour les extensions de partage consiste à gérer elles-mêmes tout le travail nécessaire. Les extensions peuvent partager du code avec les applications qu'elles contiennent en utilisant des frameworks personnalisés, donc dans la plupart des cas, ce n'est pas un problème.
Si vous souhaitez rendre des données disponibles pour votre application, vous pouvez configurer un groupe d'applications de sorte à disposer d'un répertoire partagé. L'extension peut y écrire des données et l'application peut les lire. Cela ne se produira pas avant la prochaine fois que l'utilisateur lancera l'application.
Solution de travail dans Swift 3.1 (testée dans iOS10):
Vous devez créer votre propre schéma d'URL , puis ajouter cette fonction à votre ViewController et l'appeler avec openURL("myScheme://myIdentifier")
.
// Function must be named exactly like this so a selector can be found by the compiler!
// Anyway - it's another selector in another instance that would be "performed" instead.
func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
Édition: Notes pour clarification: openURL
est une méthode d’UIApplication - puisque votre ShareExtension n’est pas dérivée de UIApplication, j’ai ajouté ma propre openURL
avec la même définition que celle d’UIApplication pour que le compilateur reste heureux ( de sorte que #selector (openURL (_ :) peut être trouvé).
Ensuite, je passe en revue les répondants jusqu'à ce que j'en trouve un qui dérive vraiment de UIApplication
et que j'appelle openURL
à ce sujet.
Un exemple plus détaillé de code qui copie les fichiers d’un ShareExtension dans un répertoire local, en sérialisant les noms de fichiers et en appelant openURL sur une autre application:
//
// ShareViewController.Swift
//
import UIKit
import Social
import MobileCoreServices
class ShareViewController: UIViewController {
var docPath = ""
override func viewDidLoad() {
super.viewDidLoad()
let containerURL = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "group.com.my-domain")!
docPath = "\(containerURL.path)/share"
// Create directory if not exists
do {
try FileManager.default.createDirectory(atPath: docPath, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
print("Could not create the directory \(error)")
} catch {
fatalError()
}
// removing previous stored files
let files = try! FileManager.default.contentsOfDirectory(atPath: docPath)
for file in files {
try? FileManager.default.removeItem(at: URL(fileURLWithPath: "\(docPath)/\(file)"))
}
}
override func viewDidAppear(_ animated: Bool) {
let alertView = UIAlertController(title: "Export", message: " ", preferredStyle: .alert)
self.present(alertView, animated: true, completion: {
let group = DispatchGroup()
NSLog("inputItems: \(self.extensionContext!.inputItems.count)")
for item: Any in self.extensionContext!.inputItems {
let inputItem = item as! NSExtensionItem
for provider: Any in inputItem.attachments! {
let itemProvider = provider as! NSItemProvider
group.enter()
itemProvider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { data, error in
if error == nil {
// Note: "data" may be another type (e.g. Data or UIImage). Casting to URL may fail. Better use switch-statement for other types.
// "screenshot-tool" from iOS11 will give you an UIImage here
let url = data as! URL
let path = "\(self.docPath)/\(url.pathComponents.last ?? "")"
print(">>> sharepath: \(String(describing: url.path))")
try? FileManager.default.copyItem(at: url, to: URL(fileURLWithPath: path))
} else {
NSLog("\(error)")
}
group.leave()
}
}
}
group.notify(queue: DispatchQueue.main) {
NSLog("done")
let files = try! FileManager.default.contentsOfDirectory(atPath: self.docPath)
NSLog("directory: \(files)")
// Serialize filenames, call openURL:
do {
let jsonData : Data = try JSONSerialization.data(
withJSONObject: [
"action" : "incoming-files"
],
options: JSONSerialization.WritingOptions.init(rawValue: 0))
let jsonString = (NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let result = self.openURL(URL(string: "myapp://com.myapp.share?\(jsonString!)")!)
} catch {
alertView.message = "Error: \(error.localizedDescription)"
}
self.dismiss(animated: false) {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
})
}
// Function must be named exactly like this so a selector can be found by the compiler!
// Anyway - it's another selector in another instance that would be "performed" instead.
func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
}
J'ai ouvert l'application hôte à partir d'une extension partagée avec une astuce. Utilisation d'une vue Web avec une couleur d'arrière-plan claire. Est le code ci-dessous.
NSString *customURL = @"MY_Host_URL_SCHEME_APP://";
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 400)];
webView.backgroundColor = [UIColor clearColor];
webView.tintColor = [UIColor clearColor];
[webView setOpaque:NO];
[self.view addSubview:webView];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:customURL]];
[webView loadRequest:urlRequest];
[self didSelectCancel];
Implémentez un schéma d'URL personnalisé dans l'application hôte et appelez la méthode openURL (url :)
comme openURL (url: NSURL (string: "nom_schéma: //"))
extension SLComposeServiceViewController {
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)
}
}
Techniquement, vous ne pouvez pas ouvrir une application contenant une extension de partage, mais vous pouvez planifier une notification locale, et c'est ce que je finis par faire. Juste avant d'appeler super.didSelectPost, je planifie une notification locale avec du texte. Si un utilisateur souhaite ouvrir une application contenant l'application, il peut le faire, sinon, il peut poursuivre son flux de travail. Je pense même que c'est une meilleure approche que d'ouvrir automatiquement l'application contenant et de perturber ce qu'ils font.
J'avais ce problème et dans iOS 11+, aucune des réponses précédentes ne fonctionne. J'ai fini par ajouter un gestionnaire d'achèvement à mon code JavaScript, puis à partir de window.location="myapp://"
. C'est un peu hacky mais cela ne semble pas trop grave et l'utilisateur peut suivre.
Non seulement il n’ya aucun moyen (et ne le sera pas) de faire cela: Il n’ya pas BESOIN de gérer cela dans l’application. L’extension est supposée gérer cela avec le très même base de code que l'application principale. Vous devez créer une structure Avec une API sécurisée pour l'extension partagée entre l'application et les cibles externes.
Voici le sujet principal ici: https://developer.Apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//Apple_ref/doc/uid/TP40014214- CH21-SW1