capacitor-docs icon indicating copy to clipboard operation
capacitor-docs copied to clipboard

Creating native classes

Open jdnichollsc opened this issue 4 years ago • 4 comments

Hello folks,

I was wondering if exist any example to create native classes? e.g: https://github.com/proyecto26/nativescript-inappbrowser/blob/develop/src/InAppBrowser.ios.ts#L36

Thanks for your help! <3

jdnichollsc avatar Mar 18 '21 15:03 jdnichollsc

Hello, I'm testing this plugin and I'm getting this error

CONSOLE LOG file:///public/nativescript/index.js:794:16: Hello iOS 👋 🎉 ~ NativeScript Team
⚡️  Loading app at capacitor://localhost...
⚡️  To Native ->  NativeScriptCap addListener 22549302
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1

⚡️  ------ STARTUP JS ERROR ------

⚡️  TypeError: Cannot convert a symbol to a string
⚡️  URL: capacitor://localhost/static/js/6.a9603605.chunk.js
⚡️  6.a9603605.chunk.js:2:115618

⚡️  See above for help with debugging blank-screen issues
⚡️  WebView loaded
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  [error] - {"line":2,"column":115618,"sourceURL":"capacitor://localhost/static/js/6.a9603605.chunk.js"}
⚡️  TO JS {"platform":false,"tracking":-1,"cmd":6}
⚡️  To Native ->  NativeScriptCap notify -1
⚡️  To Native ->  NativeScriptCap notify -1

check the code below:

import { native, nativeAPI } from '@nativescript/capacitor';

type SFSafariViewController = nativeAPI.SFSafariViewController;
type ASWebAuthenticationSession = nativeAPI.ASWebAuthenticationSession;
type SFSafariViewControllerDelegate = nativeAPI.SFSafariViewControllerDelegate;
type UIAdaptivePresentationControllerDelegate = nativeAPI.UIAdaptivePresentationControllerDelegate;
type ASWebAuthenticationPresentationContextProviding = nativeAPI.ASWebAuthenticationPresentationContextProviding;

const {
  NSObject,
  NSURL,
  SFSafariViewControllerConfiguration,
  SFSafariViewController,
  UIApplication
} = native;

class InAppBrowserModule
  extends NSObject
  implements
    SFSafariViewControllerDelegate,
    UIAdaptivePresentationControllerDelegate,
    ASWebAuthenticationPresentationContextProviding
{
  public async open (
    authUrl: string,
    options?: any
  ) {
    const url = NSURL.URLWithString(authUrl);
    const config = SFSafariViewControllerConfiguration.alloc().init();
    config.barCollapsingEnabled = options.barCollapsingEnabled;
    config.entersReaderIfAvailable = options.readerMode;
    const safariVC = SFSafariViewController.alloc().initWithURLConfiguration(url, config);
    safariVC.delegate = this;
    const ctrl = UIApplication.sharedApplication.keyWindow.rootViewController;
    ctrl.presentViewControllerAnimatedCompletion(safariVC, options.animated, () => null);
  }

  public presentationAnchorForWebAuthenticationSession(_: ASWebAuthenticationSession) {
    return UIApplication.sharedApplication.keyWindow;
  }
  public safariViewControllerDidFinish(controller: SFSafariViewController): void {
    // TODO: Resolve promise
    console.log('BROWSER Closed')
  }
}

native.InAppBrowser = <InAppBrowserModule>InAppBrowserModule.new()

Please let me know what you think, thanks in advance!

jdnichollsc avatar Mar 20 '21 07:03 jdnichollsc

Hello folks, now I'm getting another error:

file:///public/nativescript/index.js:1602:18: JS ERROR ReferenceError: Can't find variable: window
2021-03-21 19:09:29.584023-0500 App[15212:713562] *** Terminating app due to uncaught exception 'NativeScript encountered a fatal error: ReferenceError: Can't find variable: window

But I'm not using window or something like that, this is my code:

import { native, nativeAPI } from '@nativescript/capacitor';
import '@nativescript/capacitor/bridge';

type SFSafariViewController = nativeAPI.SFSafariViewController;
type ASWebAuthenticationSession = nativeAPI.ASWebAuthenticationSession;
type SFSafariViewControllerDelegate = nativeAPI.SFSafariViewControllerDelegate;
type UIAdaptivePresentationControllerDelegate = nativeAPI.UIAdaptivePresentationControllerDelegate;
type ASWebAuthenticationPresentationContextProviding = nativeAPI.ASWebAuthenticationPresentationContextProviding;

@NativeClass()
class InAppBrowserModule
  extends native.NSObject
  implements
    SFSafariViewControllerDelegate,
    UIAdaptivePresentationControllerDelegate,
    ASWebAuthenticationPresentationContextProviding
{
  public static ObjCProtocols = [
    native.SFSafariViewControllerDelegate,
    native.UIAdaptivePresentationControllerDelegate,
    native.ASWebAuthenticationPresentationContextProviding
  ];

  public open (
    authUrl: string,
    options?: any
  ) {
    const url = native.NSURL.URLWithString(authUrl);
    const config = native.SFSafariViewControllerConfiguration.alloc().init();
    config.barCollapsingEnabled = options.barCollapsingEnabled;
    config.entersReaderIfAvailable = options.readerMode;
    const safariVC = native.SFSafariViewController.alloc().initWithURLConfiguration(url, config);
    safariVC.delegate = this;
    const ctrl = native.UIApplication.sharedApplication.keyWindow.rootViewController;
    ctrl.presentViewControllerAnimatedCompletion(safariVC, !!options.animated, () => null);
  }

  public presentationAnchorForWebAuthenticationSession(_: ASWebAuthenticationSession) {
    return native.UIApplication.sharedApplication.keyWindow;
  }
  public safariViewControllerDidFinish(controller: SFSafariViewController) {
    // TODO: Resolve promise
    //console.log('BROWSER Closed')
  }
}

let InAppBrowserModuleInstance: any;

if (typeof InAppBrowserModuleInstance === 'undefined') {
  InAppBrowserModuleInstance = InAppBrowserModule.new();
}

native.InAppBrowser = <InAppBrowserModule>InAppBrowserModuleInstance

Thanks for your help! <3

jdnichollsc avatar Mar 22 '21 00:03 jdnichollsc

Hi @jdnichollsc thanks for mentioning this. We will add a page to the docs about this specifically. Basically what it comes down to is where/when you need to import { native } from '@nativescript/capacitor';.

The answer is never from within the src/nativescript folder. Inside there, native is globally and inherently accessible all the time.

You only ever need to import { native } from '@nativescript/capacitor'; from within your web components to access the native api helper methods you add (augmented by native-custom.d.ts).

NathanWalker avatar Jun 11 '21 18:06 NathanWalker

Further when creating your InAppBrowser class you did everything above well. Only need to modify like this:

// you don't need to declare this if you have typings for them already
// you can include the typings in the src/nativescript/references.d.ts
// but you can also do this:
declare var SFSafariViewControllerDelegate, UIAdaptivePresentationControllerDelegate, ASWebAuthenticationPresentationContextProviding;
// also make sure Capacitor Podfile for example includes the pod for inappbrowser if a Cocoapod is used for it.

@NativeClass()
class InAppBrowserModule extends NSObject {
  public static ObjCProtocols = [
    SFSafariViewControllerDelegate,
    UIAdaptivePresentationControllerDelegate,
    ASWebAuthenticationPresentationContextProviding
  ];

The src/nativescript folder is a full blown {N} environment meaning you can type/use {N} as you may already be used to.

The other recommendation is to create helper methods to create and do the things you need to call on from your web components, for example using example above, something like this would be nice:


native.openInAppBrowser = (authUrl: string, options?: any) => {
  if (typeof InAppBrowserModuleInstance === 'undefined') {
    InAppBrowserModuleInstance = InAppBrowserModule.new();
  }
  InAppBrowserModuleInstance.open(authUrl, options);
}

NathanWalker avatar Jun 11 '21 18:06 NathanWalker