Skip to content

Commit

Permalink
feat(iOS): Open CAPBridgeViewController for subclassing (#3973)
Browse files Browse the repository at this point in the history
  • Loading branch information
ikeith authored Dec 23, 2020
1 parent f9100da commit a601705
Show file tree
Hide file tree
Showing 9 changed files with 289 additions and 214 deletions.
418 changes: 214 additions & 204 deletions ios/Capacitor/Capacitor/CAPBridgeViewController.swift

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions ios/Capacitor/Capacitor/CAPInstanceConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ NS_SWIFT_NAME(InstanceConfiguration)
@property (nonatomic, readonly) BOOL cordovaDeployDisabled;
@property (nonatomic, readonly) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
@property (nonatomic, readonly, nonnull) NSURL *appLocation;
@property (nonatomic, readonly, nullable) NSString *appStartPath;

@property (nonatomic, readonly, nonnull) NSDictionary *legacyConfig DEPRECATED_MSG_ATTRIBUTE("Use direct properties instead");

- (instancetype _Nonnull)initWithDescriptor:(CAPInstanceDescriptor* _Nonnull)descriptor NS_SWIFT_NAME(init(with:));
- (instancetype _Nonnull)updatingAppLocation:(NSURL* _Nonnull)location NS_SWIFT_NAME(updatingAppLocation(_:));
@end

#endif /* CAPInstanceConfiguration_h */
40 changes: 33 additions & 7 deletions ios/Capacitor/Capacitor/CAPInstanceConfiguration.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#import "CAPInstanceConfiguration.h"
#import <Capacitor/Capacitor-Swift.h>

@interface CAPInstanceConfiguration (Internal)
- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location;
@end


@implementation CAPInstanceConfiguration

- (instancetype)initWithDescriptor:(CAPInstanceDescriptor *)descriptor {
Expand All @@ -18,6 +23,7 @@ - (instancetype)initWithDescriptor:(CAPInstanceDescriptor *)descriptor {
_handleApplicationNotifications = descriptor.handleApplicationNotifications;
_contentInsetAdjustmentBehavior = descriptor.contentInsetAdjustmentBehavior;
_appLocation = descriptor.appLocation;
_appStartPath = descriptor.appStartPath;
_pluginConfigurations = descriptor.pluginConfigurations;
_legacyConfig = descriptor.legacyConfig;
// construct the necessary URLs
Expand All @@ -29,15 +35,35 @@ - (instancetype)initWithDescriptor:(CAPInstanceDescriptor *)descriptor {
_serverURL = _localURL;
}
// extract the one value we care about from the cordova configuration
id value = [descriptor.cordovaConfiguration.settings objectForKey:[@"DisableDeploy" lowercaseString]];
if (value != nil && [value isKindOfClass:[NSString class]]) {
_cordovaDeployDisabled = [(NSString*)value boolValue];
}
else {
_cordovaDeployDisabled = false;
}
_cordovaDeployDisabled = [descriptor cordovaDeployDisabled];
}
return self;
}

- (instancetype)initWithConfiguration:(CAPInstanceConfiguration*)configuration andLocation:(NSURL*)location {
if (self = [super init]) {
_appendedUserAgentString = [[configuration appendedUserAgentString] copy];
_overridenUserAgentString = [[configuration overridenUserAgentString] copy];
_backgroundColor = configuration.backgroundColor;
_allowedNavigationHostnames = [[configuration allowedNavigationHostnames] copy];
_localURL = [[configuration localURL] copy];
_serverURL = [[configuration serverURL] copy];
_pluginConfigurations = [[configuration pluginConfigurations] copy];
_enableLogging = configuration.enableLogging;
_enableScrolling = configuration.enableScrolling;
_allowLinkPreviews = configuration.allowLinkPreviews;
_handleApplicationNotifications = configuration.handleApplicationNotifications;
_cordovaDeployDisabled = configuration.cordovaDeployDisabled;
_contentInsetAdjustmentBehavior = configuration.contentInsetAdjustmentBehavior;
_legacyConfig = [[configuration legacyConfig] copy];
_appStartPath = configuration.appStartPath;
_appLocation = [location copy];
}
return self;
}

- (instancetype)updatingAppLocation:(NSURL*)location {
return [[CAPInstanceConfiguration alloc] initWithConfiguration:self andLocation:location];
}

@end
14 changes: 14 additions & 0 deletions ios/Capacitor/Capacitor/CAPInstanceConfiguration.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import Foundation

extension InstanceConfiguration {
@objc var appStartFileURL: URL {
if let path = appStartPath {
return appLocation.appendingPathComponent(path)
}
return appLocation
}

@objc var appStartServerURL: URL {
if let path = appStartPath {
return serverURL.appendingPathComponent(path)
}
return serverURL
}

@objc public func getPluginConfigValue(_ pluginId: String, _ configKey: String) -> Any? {
return (pluginConfigurations as? JSObject)?[keyPath: KeyPath("\(pluginId).\(configKey)")]
}
Expand Down
13 changes: 13 additions & 0 deletions ios/Capacitor/Capacitor/CAPInstanceDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,25 @@ NS_SWIFT_NAME(InstanceDescriptor)
@property (nonatomic, assign) BOOL handleApplicationNotifications;
@property (nonatomic, assign) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
@property (nonatomic, copy, nonnull) NSURL *appLocation;
@property (nonatomic, copy, nullable) NSString *appStartPath;
@property (nonatomic, copy, nonnull) CDVConfigParser *cordovaConfiguration;
@property (nonatomic, assign) CAPInstanceWarning warnings;
@property (nonatomic, readonly) CAPInstanceType instanceType;
@property (nonatomic, retain, nonnull) NSDictionary *legacyConfig;

/**
Initialize the descriptor with the default environment. This assumes that the application was built with the help of the Capacitor CLI
and that that the web app is located inside the application bundle at `public/`.
*/
- (instancetype _Nonnull)initAsDefault NS_SWIFT_NAME(init());

/**
Initialize the descriptor for use in other contexts. The app location is the one required parameter.
@param appURL The location of the folder containing the web app.
@param configURL The location of the Capacitor configuration file.
@param cordovaURL The location of the Cordova configuration file.
*/
- (instancetype _Nonnull)initAtLocation:(NSURL* _Nonnull)appURL configuration:(NSURL* _Nullable)configURL cordovaConfiguration:(NSURL* _Nullable)cordovaURL NS_SWIFT_NAME(init(at:configuration:cordovaConfiguration:));
@end

Expand Down
2 changes: 2 additions & 0 deletions ios/Capacitor/Capacitor/CAPInstanceDescriptor.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ - (void)_setDefaultsWithAppLocation:(NSURL*)location {
_warnings = 0;
if (location == nil) {
_warnings |= CAPInstanceWarningMissingAppDir;
// location is nil so assume it was supposed to be the default
_appLocation = [[[NSBundle mainBundle] resourceURL] URLByAppendingPathComponent:@"public"];
}
}
@end
8 changes: 8 additions & 0 deletions ios/Capacitor/Capacitor/CAPInstanceDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ internal extension InstanceDescriptor {
}

extension InstanceDescriptor {
@objc public var cordovaDeployDisabled: Bool {
return (cordovaConfiguration.settings?["DisableDeploy".lowercased()] as? NSString)?.boolValue ?? false
}

@objc public func normalize() {
// first, make sure the scheme is valid
var schemeValid = false
Expand All @@ -116,6 +120,10 @@ extension InstanceDescriptor {
if !urlValid {
serverURL = nil
}
// reset the path if it's not valid
if let path = appStartPath?.trimmingCharacters(in: .whitespacesAndNewlines), path.isEmpty {
appStartPath = nil
}
// if the plugin configuration was programmatically modified, the necessary type information may have been lost.
// so perform a coercion here to make sure that casting will work as expected
pluginConfigurations = JSTypes.coerceDictionaryToJSObject(pluginConfigurations) ?? [:]
Expand Down
2 changes: 1 addition & 1 deletion ios/Capacitor/Capacitor/CapacitorBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ internal class CapacitorBridge: NSObject, CAPBridgeProtocol {

var lastPlugin: CAPPlugin?

@objc public var config: InstanceConfiguration
@objc public internal(set) var config: InstanceConfiguration
// Map of all loaded and instantiated plugins by pluginId -> instance
var plugins = [String: CAPPlugin]()
// List of known plugins by pluginId -> Plugin Type
Expand Down
4 changes: 2 additions & 2 deletions ios/Capacitor/Capacitor/WebViewDelegationHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ internal class WebViewDelegationHandler: NSObject, WKNavigationDelegate, WKUIDel
contentController.removeScriptMessageHandler(forName: handlerName)
}

func willLoadWebview(_ webView: WKWebView) {
func willLoadWebview(_ webView: WKWebView?) {
// Set the webview to be not opaque on the inital load. This prevents
// the webview from showing a white background, which is its default
// loading display, as that can appear as a screen flash. The opacity
// might have been set by something else, like a plugin, so we want
// to save the current value so it can be reset on success or failure.
if case .unloaded = webViewLoadingState {
if let webView = webView, case .unloaded = webViewLoadingState {
webViewLoadingState = .initialLoad(isOpaque: webView.isOpaque)
webView.isOpaque = false
}
Expand Down

0 comments on commit a601705

Please sign in to comment.