@embrace-io/react-native
Version:
A React Native wrapper for the Embrace SDK
187 lines (185 loc) • 10.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.withIosEmbraceAddUploadPhase = exports.withIosEmbraceAddBridgingHeader = exports.withIosEmbraceInvokeInitializer = exports.withIosEmbraceAddInitializer = void 0;
const config_plugins_1 = require("@expo/config-plugins");
const xcodeproj_1 = require("./xcodeproj");
const textUtils_1 = require("./textUtils");
const fileUtils_1 = require("./fileUtils");
const path = require("path");
const fs = require("fs");
const importAppDelegateHeaderRE = /(\s*)#import "AppDelegate\.h"/;
const objcAppLaunchRE = /(\s*)self.moduleName = @"main"/;
const swifthAppLaunchRE = /(\s*)func\s+application\(\s*_\s*[^}]*\{/;
const swifthUpdatedAppLaunchRE = /(\s*)let.*ExpoReactNativeFactory.*/;
const rnBundleScript = "react-native-xcode.sh";
const sourceMapPath = "$CONFIGURATION_BUILD_DIR/embrace-assets/main.jsbundle.map";
const exportSourcemapLine = `export SOURCEMAP_FILE="${sourceMapPath}"`;
const getEmbraceInitializerContents = (appId) => {
return `import Foundation
import EmbraceIO
@objcMembers class EmbraceInitializer: NSObject {
// Start the EmbraceSDK with the minimum required settings, for more advanced configuration options see:
// https://embrace.io/docs/ios/open-source/integration/embrace-options/
static func start() -> Void {
do {
try Embrace
.setup(
options: Embrace.Options(
appId: "${appId}",
platform: .reactNative
)
)
.start()
} catch let e {
print("Error starting Embrace \\(e.localizedDescription)")
}
}
}
`;
};
const getBridgingHeaderContents = () => {
return `//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
`;
};
const withIosEmbraceAddInitializer = (expoConfig, props) => {
return (0, config_plugins_1.withXcodeProject)(expoConfig, (config) => __awaiter(void 0, void 0, void 0, function* () {
const project = config.modResults;
const projectName = config.modRequest.projectName || "";
const filePath = path.join(config.modRequest.platformProjectRoot, projectName, "EmbraceInitializer.swift");
(0, fileUtils_1.writeIfNotExists)(filePath, getEmbraceInitializerContents(props.iOSAppId), "withIosEmbraceAddInitializer");
const projectRelativePath = path.join(projectName, "EmbraceInitializer.swift");
if (!project.hasFile(projectRelativePath)) {
(0, xcodeproj_1.addFile)(project, projectName, projectRelativePath, "source");
fs.writeFileSync(project.filepath, project.writeSync());
}
return config;
}));
};
exports.withIosEmbraceAddInitializer = withIosEmbraceAddInitializer;
const withIosEmbraceInvokeInitializer = (expoConfig, props) => {
return (0, config_plugins_1.withAppDelegate)(expoConfig, config => {
const lines = config.modResults.contents.split("\n");
const language = config.modResults.language;
// Don't add the Embrace initialize line again if it's already there
if ((0, textUtils_1.hasMatch)(lines, "Embrace")) {
return config;
}
// Add the objective-c bridging header import if required
if (language === "objcpp") {
// https://developer.apple.com/documentation/swift/importing-swift-into-objective-c#Overview
const headerName = props.productModuleName || config.modRequest.projectName || "";
const alphanumericOnly = headerName.replace(/\W+/g, "_");
const firstNumberReplaced = alphanumericOnly.replace(/^\d/, "_");
const bridgingHeaderName = `${firstNumberReplaced}-Swift.h`;
if (!bridgingHeaderName) {
throw new Error("failed to determine bridging header name for the AppDelegate file");
}
const addedImport = (0, textUtils_1.addAfter)(lines,
// Look for the import of AppDelegate.h and add the import underneath
importAppDelegateHeaderRE, `#import "${bridgingHeaderName}"`);
if (!addedImport) {
throw new Error("failed to add the bridging header import to the AppDelegate file");
}
const addedExpoModulesImport = (0, textUtils_1.addAfter)(lines,
// Look for the import of AppDelegate.h and add the import underneath
importAppDelegateHeaderRE, `#import "ExpoModulesCore-Swift.h"`);
if (!addedExpoModulesImport) {
throw new Error("failed to add the expo modules import to the AppDelegate file");
}
}
const addedInit = (0, textUtils_1.addAfter)(lines,
// Want the Embrace SDK initialization to happen right after at the start of the AppDelegate application method
language === "swift" ? swifthAppLaunchRE : objcAppLaunchRE, language === "swift"
? " EmbraceInitializer.start()" // Add indentation since we're matching on the method signature's whitespace
: "[EmbraceInitializer start];");
if (!addedInit) {
if (language !== "swift") {
throw new Error("failed to add the Embrace initialization to the AppDelegate application method");
}
// Default AppDelegate.swift changed on later versions of expo, try one more time with a different regex
const addedInitUpdatedSwift = (0, textUtils_1.addAfter)(lines, swifthUpdatedAppLaunchRE, "EmbraceInitializer.start()");
if (!addedInitUpdatedSwift) {
throw new Error("failed to add the Embrace initialization to the AppDelegate application method");
}
}
config.modResults.contents = lines.join("\n");
return config;
});
};
exports.withIosEmbraceInvokeInitializer = withIosEmbraceInvokeInitializer;
const withIosEmbraceAddBridgingHeader = expoConfig => {
return (0, config_plugins_1.withXcodeProject)(expoConfig, (config) => __awaiter(void 0, void 0, void 0, function* () {
const project = config.modResults;
const projectName = config.modRequest.projectName || "";
const bridgingHeader = project.getBuildProperty("SWIFT_OBJC_BRIDGING_HEADER", undefined, projectName);
if (bridgingHeader) {
// Nothing to do if the bridging header already exists;
return config;
}
const filename = `${projectName}-Bridging-Header.h`;
const filePath = path.join(config.modRequest.platformProjectRoot, projectName, filename);
const projectRelativePath = path.join(projectName, filename);
(0, fileUtils_1.writeIfNotExists)(filePath, getBridgingHeaderContents(), "withIosEmbraceAddBridgingHeader");
if (!project.hasFile(projectRelativePath)) {
(0, xcodeproj_1.addFile)(project, projectName, projectRelativePath, "resource");
(0, xcodeproj_1.updateBuildProperty)(project, projectName, "SWIFT_OBJC_BRIDGING_HEADER", `"${projectRelativePath}"`);
fs.writeFileSync(project.filepath, project.writeSync());
}
return config;
}));
};
exports.withIosEmbraceAddBridgingHeader = withIosEmbraceAddBridgingHeader;
const withIosEmbraceAddUploadPhase = (expoConfig, props) => {
return (0, config_plugins_1.withXcodeProject)(expoConfig, (config) => __awaiter(void 0, void 0, void 0, function* () {
let modified = false;
const project = config.modResults;
const bundlePhase = (0, xcodeproj_1.findPhase)(project, rnBundleScript);
if (!bundlePhase) {
throw new Error("Could not find React Native bundle phase to modify");
}
if (!(0, textUtils_1.hasMatch)(bundlePhase.code, "embrace-assets")) {
(0, xcodeproj_1.modifyPhase)(project, bundlePhase.key, /^.*?\/(packager|scripts)\/react-native-xcode\.sh\s*/m, `mkdir -p "$CONFIGURATION_BUILD_DIR/embrace-assets"\n` +
`${exportSourcemapLine}\n`);
modified = true;
}
/*
shellScript = "REACT_NATIVE_MAP_PATH=\"$CONFIGURATION_BUILD_DIR/embrace-assets/main.jsbundle.map\" EMBRACE_ID=ios789 EMBRACE_TOKEN=apiToken456 \"${PODS_ROOT}/EmbraceIO/run.sh\"\nrm \"$CONFIGURATION_BUILD_DIR/embrace-assets/main.jsbundle.map\"";
*/
if (!(0, xcodeproj_1.findPhase)(project, "EmbraceIO/run.sh")) {
project.addBuildPhase([], "PBXShellScriptBuildPhase", "Upload Debug Symbols to Embrace", null, {
shellPath: "/bin/sh",
shellScript: `REACT_NATIVE_MAP_PATH="${sourceMapPath}" EMBRACE_ID=${props.iOSAppId} EMBRACE_TOKEN=${props.apiToken} "\${PODS_ROOT}/EmbraceIO/run.sh"`,
});
modified = true;
}
if (modified) {
fs.writeFileSync(project.filepath, project.writeSync());
}
return config;
}));
};
exports.withIosEmbraceAddUploadPhase = withIosEmbraceAddUploadPhase;
const withIosEmbrace = (config, props) => {
try {
config = withIosEmbraceAddInitializer(config, props);
config = withIosEmbraceInvokeInitializer(config, props);
config = withIosEmbraceAddBridgingHeader(config, props);
config = withIosEmbraceAddUploadPhase(config, props);
}
catch (e) {
config_plugins_1.WarningAggregator.addWarningIOS("@embrace-io/expo-config-plugin", e instanceof Error ? e.message : "", "https://embrace.io/docs/react-native/integration/add-embrace-sdk/");
}
return config;
};
exports.default = withIosEmbrace;