问题
I have problems with creating share extension like share extension of the Pinterest app. When user is not logged to the containing app the share extension only presents alert with an option to log in
and cancel
.
Where in code decide which view controller to show in my shared extension. I see this like I need to check authorization status from shared container and if this status is not logged
I need to present alert controller. If status is logged
I need to show my main view controller ShareViewController
which is a subclass of SLComposeServiceViewController
My question is not UI related but where to put this check code. I didn't find any method where app extension starts so I can select some initial view controller for extension based on some state.
In Pinterest extension I don't see their main view controller when user is logged out from their containing app. I see only alert with options.
Second question: How to programatically switch from share extension to containing app. How this Pinterest share extension is doing this when user need to authenticate?
I'm working on latest iOS SDK 10.2
回答1:
Since I didn't receive any feedback for this and I figure it out how to do this. Here is the answer.
To control which view load I used loadView
method from UIViewController
lifecycle. This method is fired when application first need to get view
property from UIViewController
. So this is lazy loading. This method is also fired when user invoke loadViewIfNeeded()
from UIViewController
api. In the body of this method You need to be very careful to not read view
property because this will invoke loadView
again and You will have recursive loop.
My implementation for this method is following. I need to tell if user is logged in or not in containing app and based on this choose which view to load.
override func loadView() {
// check in shared Keychain if user is authenticated
self.userAuthenticated = userService.isAuthenticated()
if self.userAuthenticated {
// load default view of the ShareViewController
super.loadView()
} else {
// if user is not logged in show only alert view controller with transparent dummy view
let view = UIView()
self.view = view
}
}
And if user is not logged in I show alert in
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let context = self.extensionContext!
if !self.userAuthenticated {
let alert = UIAlertController(title: "Error", message: "User not logged in", preferredStyle: .alert)
let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in
context.completeRequest(returningItems: nil, completionHandler: nil)
}
let login = UIAlertAction(title: "Log In", style: .default, handler: { _ in
let url = URL(string: "fashionapp://login")!
// This is utility method written in Objective-C.
// I don't know yet if it passes Apple Review process or not.
// We will see ;)
self.open(url, options: [:], completionHandler: nil)
context.completeRequest(returningItems: nil, completionHandler: nil)
})
alert.addAction(cancel)
alert.addAction(login)
present(alert, animated: true, completion: nil)
}
}
And here is the method for opening containing app from share extension. I hope it will be useful and Apple will review this without any problems. It is written in Objective-C
because in Swift
there is no NSInvocation
class so you can only perform selectors with max two arguments.
#import <UIKit/UIKit.h>
@interface UIViewController (OpenURL)
- (void)openURL:(nonnull NSURL *)url
options:(nonnull NSDictionary<NSString *, id> *)options
completionHandler:(void (^ __nullable)(BOOL success))completion;
@end
And implementation.
#import "UIViewController+OpenURL.h"
@implementation UIViewController (OpenURL)
- (void)openURL:(nonnull NSURL *)url
options:(nonnull NSDictionary<NSString *, id> *)options
completionHandler:(void (^ __nullable)(BOOL success))completion {
SEL selector = NSSelectorFromString(@"openURL:options:completionHandler:");
UIResponder* responder = self;
while ((responder = [responder nextResponder]) != nil) {
if([responder respondsToSelector:selector] == true) {
NSMethodSignature *methodSignature = [responder methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
[invocation setTarget: responder];
[invocation setSelector: selector];
[invocation setArgument: &url atIndex: 2];
[invocation setArgument: &options atIndex:3];
[invocation setArgument: &completion atIndex: 4];
[invocation invoke];
break;
}
}
}
@end
来源:https://stackoverflow.com/questions/42858487/ios-share-extension-flow