Skip to content

Commit

Permalink
feat: Pass NS app to the native app instead of presenting it over the…
Browse files Browse the repository at this point in the history
… root VC (#5967)

* feat: Pass NS app native controller to the native app instead of presenting it over the rootViewController

When NativeScript embedded app is created from the native one we check for whether the topmost UIViewController has NativeScriptEmbedder protocol (implemented in the iOS Runtime) method 'presentNativeScriptApp:'. If yes, we call it with the NS app viewcontroller as a parameter so the embedder has control over the NS app (where and how to present it etc.) For backwards compatibility we present the NS app on top of the topmost UIViewController as a fallback.

* style: Fix lint errors

* feat: Check for protocol instead of selector in embedding

I

* Check for rootController instead of topViewController to prevent crash if !rootController

* feat: Introduce NativeScriptEmbedder singleton

NativeScriptEmbedder is responsive for communication between the NS and the native iOS app. His delegate will implement methods which we can call from javascript such as "presentNativeScriptApp:".
  • Loading branch information
tdermendjiev committed Jun 27, 2018
1 parent 67f9e06 commit 05c2460
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ libs
node_modules
package
platforms
!tns-core-modules/platforms
reports
tags

Expand Down
24 changes: 21 additions & 3 deletions tns-core-modules/application/application.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,26 @@ class IOSApplication implements IOSApplicationDefinition {
// TODO: Expose Window module so that it can we styled from XML & CSS
this._window.backgroundColor = utils.ios.getter(UIColor, UIColor.whiteColor);

this.notifyAppStarted(notification);

}

public notifyAppStarted(notification?: NSNotification) {
const args: LaunchEventData = {
eventName: launchEvent,
object: this,
ios: notification.userInfo && notification.userInfo.objectForKey("UIApplicationLaunchOptionsLocalNotificationKey") || null
ios: notification && notification.userInfo && notification.userInfo.objectForKey("UIApplicationLaunchOptionsLocalNotificationKey") || null
};

notify(args);
notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: getCssFileName() });

this.setWindowContent(args.root);
// this._window will be undefined when NS app is embedded in a native one
if (this._window) {
this.setWindowContent(args.root);
} else {
this._window = UIApplication.sharedApplication.delegate.window;
}
}

@profile
Expand Down Expand Up @@ -235,6 +245,7 @@ class IOSApplication implements IOSApplicationDefinition {
this._window.makeKeyAndVisible();
}
}

}

const iosApp = new IOSApplication();
Expand Down Expand Up @@ -296,7 +307,14 @@ export function start(entry?: string | NavigationEntry) {
if (rootController) {
const controller = getViewController(rootView);
rootView._setupAsRootView({});
rootController.presentViewControllerAnimatedCompletion(controller, true, null);
let embedderDelegate = NativeScriptEmbedder.sharedInstance().delegate;
if (embedderDelegate) {
embedderDelegate.performSelectorWithObject("presentNativeScriptApp:", controller);
} else {
let visibleVC = utils.ios.getVisibleViewController(rootController);
visibleVC.presentViewControllerAnimatedCompletion(controller, true, null);
}
iosApp.notifyAppStarted();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tns-core-modules/platforms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
## Platform specific native code
26 changes: 26 additions & 0 deletions tns-core-modules/platforms/ios/src/NativeScriptEmbedder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// NativeScriptEmbedder.h
// NativeScript
//
// Created by Teodor Dermendzhiev on 6/19/18.
//
#include <UIKit/UIKit.h>

// When embedding NativeScript application embedder needs to conform to this protocol
// in order to have control over the NativeScript UIViewController
// otherwise NativeScript application is presented over the topmost UIViewController.
@protocol NativeScriptEmbedderDelegate
- (id)presentNativeScriptApp:(UIViewController*)vc;
@end

@interface NativeScriptEmbedder : NSObject

@property(nonatomic, retain, readonly) id<NativeScriptEmbedderDelegate> delegate;

+ (NativeScriptEmbedder *)sharedInstance;

- (void)setDelegate:(id <NativeScriptEmbedderDelegate>)aDelegate;


@end

19 changes: 19 additions & 0 deletions tns-core-modules/platforms/ios/src/NativeScriptEmbedder.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#import "NativeScriptEmbedder.h"

@implementation NativeScriptEmbedder

+ (NativeScriptEmbedder *)sharedInstance {
static NativeScriptEmbedder *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[NativeScriptEmbedder alloc] init];
});

return sharedInstance;
}

- (void)setDelegate:(id <NativeScriptEmbedderDelegate>)aDelegate {
_delegate = aDelegate;
}

@end
4 changes: 4 additions & 0 deletions tns-core-modules/platforms/ios/src/module.modulemap
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module NativeScriptEmbedder {
header "NativeScriptEmbedder.h"
export *
}
11 changes: 11 additions & 0 deletions tns-core-modules/tns-core-modules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,14 @@ interface Array<T> {
//Dialogs
declare function alert(message?: any): void;
declare function confirm(message?: string): boolean;

// Embedding
declare interface NativeScriptEmbedderDelegate /* NSObject */ {
presentNativeScriptApp(any/* UIViewController*/): any;
performSelectorWithObject(string, any): any;
}

declare class NativeScriptEmbedder {
public static sharedInstance(): NativeScriptEmbedder;
public delegate: NativeScriptEmbedderDelegate;
}
7 changes: 7 additions & 0 deletions tns-core-modules/utils/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ export module ios {
* iOS - this folder is read-only and contains the app and all its resources.
*/
export function getCurrentAppPath(): string;

/**
* Gets the currently visible(topmost) UIViewController.
* @param rootViewController The root UIViewController instance to start searching from (normally window.rootViewController).
* Returns the visible UIViewController.
*/
export function getVisibleViewController(rootViewController: any/* UIViewController*/ ): any/* UIViewController*/;
}

/**
Expand Down
19 changes: 19 additions & 0 deletions tns-core-modules/utils/utils.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,25 @@ export module ios {

return NSString.stringWithString(NSString.pathWithComponents(<any>paths)).stringByStandardizingPath;
}

export function getVisibleViewController(rootViewController: UIViewController): UIViewController {
if (rootViewController.presentedViewController) {
return getVisibleViewController(rootViewController.presentedViewController);
}

if (rootViewController.isKindOfClass(UINavigationController.class())) {
return getVisibleViewController((<UINavigationController>rootViewController).visibleViewController);
}

if (rootViewController.isKindOfClass(UITabBarController.class())) {
let selectedTab = (<UITabBarController>rootViewController).selectedViewController;
return getVisibleViewController(<UITabBarController>rootViewController);
}

return rootViewController;

}

}

export function GC() {
Expand Down

0 comments on commit 05c2460

Please sign in to comment.