Skip to content

Commit

Permalink
[iOS] Add a native module for Expo Go (expo#23730)
Browse files Browse the repository at this point in the history
  • Loading branch information
tsapeta authored Jul 26, 2023
1 parent 3d3b8e6 commit 47a99a8
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 15 deletions.
18 changes: 16 additions & 2 deletions ios/Exponent/Versioned/Core/Modules/ExpoGoModule.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
// Copyright 2023-present 650 Industries. All rights reserved.

import ExpoModulesCore
import EXManifests

final class ExpoGoModule: Module {
let manifest: Manifest

// swiftlint:disable:next unavailable_function
required init(appContext: AppContext) {
fatalError("Initializer not implemented, use init(appContext:params:manifest:) instead")
}

init(appContext: AppContext, manifest: Manifest) {
self.manifest = manifest
super.init(appContext: appContext)
}

func definition() -> ModuleDefinition {
Name("ExpoGoModule")
Name("ExpoGo")

Constants {
return [
"isDetached": false
"expoVersion": Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion"),
"projectConfig": manifest.expoGoConfigRootObject()
]
}
}
Expand Down
6 changes: 5 additions & 1 deletion ios/Exponent/Versioned/Core/VersionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ final class VersionManager: EXVersionManagerObjC {
Registers Expo modules that are not generated in ``ExpoModulesProvider``, but are necessary for Expo Go apps.
*/
private func registerExpoModules() {
appContext?.moduleRegistry.register(moduleType: ExpoGoModule.self)
guard let appContext else {
log.error("Unable to register Expo modules, the app context is unavailable")
return
}
appContext.moduleRegistry.register(module: ExpoGoModule(appContext: appContext, manifest: manifest))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import Foundation
@objc(EXManifestBaseLegacyManifest)
@objcMembers
public class BaseLegacyManifest: Manifest {
override func expoClientConfigRootObject() -> [String: Any]? {
public override func expoClientConfigRootObject() -> [String: Any]? {
return rawManifestJSON()
}

override func expoGoConfigRootObject() -> [String: Any]? {
public override func expoGoConfigRootObject() -> [String: Any]? {
return rawManifestJSON()
}

Expand Down
4 changes: 2 additions & 2 deletions packages/expo-manifests/ios/EXManifests/Manifest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,11 @@ public class Manifest: NSObject {
preconditionFailure("Must override in concrete class")
}

func expoGoConfigRootObject() -> [String: Any]? {
public func expoGoConfigRootObject() -> [String: Any]? {
preconditionFailure("Must override in concrete class")
}

func expoClientConfigRootObject() -> [String: Any]? {
public func expoClientConfigRootObject() -> [String: Any]? {
preconditionFailure("Must override in concrete class")
}

Expand Down
4 changes: 2 additions & 2 deletions packages/expo-manifests/ios/EXManifests/NewManifest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,11 @@ public class NewManifest: Manifest {
return launchAsset().requiredValue(forKey: "url")
}

override func expoClientConfigRootObject() -> [String: Any]? {
public override func expoClientConfigRootObject() -> [String: Any]? {
return extra()?.optionalValue(forKey: "expoClient")
}

override func expoGoConfigRootObject() -> [String: Any]? {
public override func expoGoConfigRootObject() -> [String: Any]? {
return extra()?.optionalValue(forKey: "expoGo")
}
}
18 changes: 14 additions & 4 deletions packages/expo-modules-core/ios/Swift/ModuleRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,26 @@ public final class ModuleRegistry: Sequence {
registry[holder.name] = holder
}

/**
Registers an instance of the module.
*/
public func register(module: AnyModule) {
guard let appContext else {
log.error("Unable to register a module '\(module)', the app context is unavailable")
return
}
register(holder: ModuleHolder(appContext: appContext, module: module))
}

/**
Registers a module by its type.
*/
public func register(moduleType: AnyModule.Type) {
guard let appContext = appContext else {
guard let appContext else {
log.error("Unable to register a module '\(moduleType)', the app context is unavailable")
return
}
let module = moduleType.init(appContext: appContext)
let holder = ModuleHolder(appContext: appContext, module: module)
register(holder: holder)
register(module: moduleType.init(appContext: appContext))
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/expo/build/Expo.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo/build/Expo.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/expo/build/Expo.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo/build/Expo.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions packages/expo/build/environment/ExpoGo.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/expo/build/environment/ExpoGo.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions packages/expo/build/environment/ExpoGo.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/expo/build/environment/ExpoGo.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/expo/src/Expo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ import * as Logs from './logs/Logs';
export { Logs };
export { disableErrorHandling } from './errors/ExpoErrorManager';
export { default as registerRootComponent } from './launch/registerRootComponent';
export { isRunningInExpoGo, getExpoGoProjectConfig } from './environment/ExpoGo';
52 changes: 52 additions & 0 deletions packages/expo/src/environment/ExpoGo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { requireNativeModule } from 'expo-modules-core';

type ExpoGoModule = {
expoVersion: string;
projectConfig: ExpoGoProjectConfig;
};

type ExpoGoProjectConfig = {
mainModuleName?: string;
debuggerHost?: string;
logUrl?: string;
developer?: {
tool?: string;
[key: string]: any;
};
packagerOpts?: ExpoGoPackagerOpts;
};

type ExpoGoPackagerOpts = {
hostType?: string;
dev?: boolean;
strict?: boolean;
minify?: boolean;
urlType?: string;
urlRandomness?: string;
lanType?: string;
[key: string]: any;
};

// ExpoGo module is available only when the app is run in Expo Go,
// otherwise we use `null` instead of throwing an error.
const NativeExpoGoModule = ((): ExpoGoModule | null => {
try {
return requireNativeModule('ExpoGo');
} catch {
return null;
}
})();

/**
* Returns a boolean value whether the app is running in Expo Go.
*/
export function isRunningInExpoGo(): boolean {
return NativeExpoGoModule != null;
}

/**
* Returns an Expo Go project config from the manifest or `null` if the app is not running in Expo Go.
*/
export function getExpoGoProjectConfig(): ExpoGoProjectConfig | null {
return NativeExpoGoModule?.projectConfig ?? null;
}

0 comments on commit 47a99a8

Please sign in to comment.