Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to officially handle unauthenticated users in an iOS share extension?

That is, what is an idiomatic way to do this that is prescribed by Apple? For any suggestion, please explain HOW that should be done and/or provide a link to official guides. This should be a common enough scenario, but I was only able to find workarounds.

Approaching this from the other end, I know that UserDefaults(suiteName:) and Keychain services can be used from the containing app to share information about the authenticated user with the extension, but what if the user installs the app and just jumps right into trying to share content using its extension without ever signing in (or up)?

  1. Ask user to sign in in the containing app? (In a custom view? Extensions are modal by default.)

  2. Re-implement authentication in extension? (Or shared via custom framework? Is this possible?)

  3. Switch to containing app and then back? This doesn't seem to be supported except in Today extension, but the mechanism described in the docs have been used for workarounds (SO threads: 1, 2, 3).


An (ugly) sample implementation of item 2 in this answer using Firebase.

like image 481
toraritte Avatar asked Dec 12 '25 18:12

toraritte


1 Answers

I couldn't find any official guidelines, but the solution below did work and also got accepted in App Store. Probably the bottom line is exactly that: (1) it shouldn't crash and (2) should be able to go through the review process.

The solution with [FirebaseUI authentication[(https://github.com/firebase/FirebaseUI-iOS):

animation

The pertinent code parts:

import UIKit
import Social
import Firebase
import FirebaseAuthUI

class ShareViewController: SLComposeServiceViewController {

    var authUI: FUIAuth?

    /* Using shared container to communicate between extension
       and containing app. Keychain would probably work too.
    */
    let defaults = UserDefaults.init(suiteName: "your-app-group")!

    override func presentationAnimationDidFinish() {

        /* https://stackoverflow.com/questions/37910766/
        */
        if FirebaseApp.app() == nil {
            FirebaseApp.configure()
        }

        self.authUI = FUIAuth.defaultAuthUI()
        self.authUI?.delegate = self

        if self.defaults.bool(forKey: "userLoggedIn") == false {
            let fuiSignin     = 
                FUIPasswordSignInViewController(
                    authUI: FUIAuth.defaultAuthUI()!,
                    email: nil)
            let navController = 
                UINavigationController(rootViewController: fuiSignin)

            self.present(navController, animated: true)
        }
    }

/* FirebaseAuthUI delegate to handle sign-in
*/
extension ShareViewController: FUIAuthDelegate {
    func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
        if error != nil {
            fatalError()
        }
        if user != nil {
            self.defaults.set(true, forKey: "userLoggedIn")
        }
    }
}

Successful sign in also gets remembered via the shared container (i.e., opening the containing app won't ask for login).

The relevant commit in the github project: https://github.com/society-for-the-blind/Access-News-Reader-iOS/commit/e752b1c554f79ef027818db35c11fceb1ae817e0


ISSUES

The first I ran it, the forms appeared, but wouldn't accept any input. Did Product > Clean and Product > Clean Build Folder ..., restarted Xcode and the Simulator, and it worked. It also worked on an old iPad (iOS 10.3.3).

like image 83
toraritte Avatar answered Dec 14 '25 12:12

toraritte