React Native Module | ASWebAuthenticationSession error on swift but not in Objective C

546 Views Asked by At

I'm working on a react native library including auth processes, So I chose ASWebAuthenticationSession to do it. My first step for this RN library was to develop natively first(in Swift). And when I started this new library it cames with both objective-c bridge and swift and I assume that both files could do the same.

But I can't run ASWebAuthenticationSession from the swift file properly where objective c runs it perfectly and I prefer to do it from Swift (If I'm wrong tell me)

The problem is that when I run code from swift the ASWebAuthenticationSession popup closes before any user input but not from objective-c . Here are my codes, if you have an idea thank you by advance.

Swift Version

//MyRnModule.m
@interface RCT_EXTERN_MODULE(MyRNModule, NSObject)

- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();
}

RCT_EXTERN_METHOD(startSecuredView:(NSURL *)uri)
//MyRnModule.swift
@objc(MyRNModule)
class MyRNModule: NSObject {
      @objc func startSecuredView(_ url: URL?) {
      if let url = url {
        if #available(iOS 12.0, *) {
          let session = ASWebAuthenticationSession(url: url, callbackURLScheme: "",  completionHandler: { (callbackURL, error) in
            print("completed")

            if let error = error {
              print("erorr \(error)")
              return
            }
            if let callbackURL = callbackURL {
              print("should handle callback \(callbackURL)")
            }
          })
          if #available(iOS 13.0, *) {
            session.presentationContextProvider = self

          }
          session.start()

        }
      } else {
        print("you must specify url")
      }
    }

}
extension MyRNModule: ASWebAuthenticationPresentationContextProviding {
    @available(iOS 13, *)
    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor{
      if let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first {
        return keyWindow
      } else {
        return ASPresentationAnchor()
      }
    }
}

Objective-C

@interface RCT_EXTERN_MODULE(MyRNModule, NSObject)

- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();
}

RCT_EXPORT_METHOD(startSecuredView:(NSURL *)url)
{
    if (!url) {
        RCTLogError(@"You must specify a url.");
        return;
    }

    if (@available(iOS 12.0, *)) {
        ASWebAuthenticationSession* session =
        [[ASWebAuthenticationSession alloc] initWithURL:url
                                      callbackURLScheme: @""
                                      completionHandler:^(NSURL * _Nullable callbackURL,
                                                          NSError * _Nullable error) {
            _authenticationVCC = nil;

            if (callbackURL) {
                [RCTSharedApplication() openURL:callbackURL];
            }
        }];

        #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
        if (@available(iOS 13.0, *)) {
            session.presentationContextProvider = self;
        }
        #endif

        _authenticationVCC = session;

        [session start];
    }
}

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
#pragma mark - ASWebAuthenticationPresentationContextProviding

- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session  API_AVAILABLE(ios(13.0)){
   return UIApplication.sharedApplication.keyWindow;
}
#endif

Codes seems to reflect same processes, just translated, I don't know what I'm missing out because call of MyRNModule. startSecuredView("https://some.url") do not behave the same

1

There are 1 best solutions below

0
On

In your Objective-C Code, you hold a "strong" reference to the session.

_authenticationVCC = session;

In your Swift Code, you do not.

The documentation states that a strong reference is mandatory for iOS < 13.0, otherwise it will be immediately removed as there is no more active reference to the session when your method ends. This results in the window getting closed.

To fix this, you could add an attribute to your class MyRNModule and assign the sessionto this attribute instead of a local constant before starting it.

class MyRNModule: NSObject {
        private var session: ASWebAuthenticationSession?
}

And later in your method:

self.session = ASWebAuthenticationSession(...)

Cite from the docs:

For iOS apps with a deployment target earlier than iOS 13, your app must keep a strong reference to the session to prevent the system from deallocating the session while waiting for authentication to complete.