smartech-base-expo-plugin
Version:
Smartech Base Expo SDK's React Native Plugin For React Native Projects.
444 lines (443 loc) • 23.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.withNetcoreiOS = void 0;
const config_plugins_1 = require("@expo/config-plugins");
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const iosConstants_1 = require("./iosConstants");
const helper_1 = require("./helper");
const addURLSchemeEntry = (existingURLTypes, urlName, urlSchema) => {
const newEntry = {
CFBundleTypeRole: "Editor",
CFBundleURLName: urlName,
CFBundleURLSchemes: [urlSchema],
};
const isNewEntryAlreadyAdded = existingURLTypes.some((entry) => (entry.CFBundleURLName === newEntry.CFBundleURLName &&
entry.CFBundleURLSchemes.includes(newEntry.CFBundleURLSchemes[0])));
if (!isNewEntryAlreadyAdded) {
existingURLTypes.push(newEntry);
}
return existingURLTypes;
};
// Set custom entitlements plist
const modifyEntitlementsPlist = (config, props) => {
return (0, config_plugins_1.withEntitlementsPlist)(config, async (newConfig) => {
newConfig.modResults = {
...newConfig.modResults,
"com.apple.security.application-groups": [`group.${props.ios.groupIdentifier}`],
};
return newConfig;
});
};
// Set custom info plist
const modifyInfoPlist = (config, props) => {
return (0, config_plugins_1.withInfoPlist)(config, (newConfig) => {
newConfig.modResults = {
...newConfig.modResults,
SmartechKeys: {
SmartechAppGroup: `group.${props.ios.groupIdentifier}`,
SmartechAppId: props.ios.appId,
SmartechAutoFetchLocation: props.ios.autoFetchLocation,
SmartechUseAdvId: props.ios.useAdvID,
},
...(props.ios.smartechNudges.smartechNudgesEnabled && {
HanselKeys: {
HanselAppId: props.ios.smartechNudges.appId,
HanselAppKey: props.ios.smartechNudges.appKey,
}
})
};
return newConfig;
});
};
const addSmartechURLScheme = (config, props) => {
return (0, config_plugins_1.withInfoPlist)(config, (newConfig) => {
if (!props.ios.addTestDevice) {
return newConfig;
}
if (props.ios.testDeviceURLName == undefined || props.ios.testDeviceURLSchema == undefined) {
console.log(`Smartech Url scheme ${props.ios.testDeviceURLName} and ${props.ios.testDeviceURLSchema}`);
return newConfig;
}
const modResults = newConfig.modResults;
const existingURLTypes = (modResults.CFBundleURLTypes || []);
modResults.CFBundleURLTypes = addURLSchemeEntry(existingURLTypes, props.ios.testDeviceURLName, props.ios.testDeviceURLSchema);
return newConfig;
});
};
const addHanselURLScheme = (config, props) => {
return (0, config_plugins_1.withInfoPlist)(config, (newConfig) => {
if (!props.ios.smartechNudges.smartechNudgesEnabled || !props.ios.smartechNudges.addTestDevice) {
return newConfig;
}
if (props.ios.smartechNudges?.testDeviceURLName == undefined || props.ios.smartechNudges?.testDeviceURLSchema == undefined) {
console.log(`Smartech Nudge Url scheme ${props.ios.smartechNudges?.testDeviceURLName} and ${props.ios.smartechNudges?.testDeviceURLSchema}`);
return newConfig;
}
const modResults = newConfig.modResults;
const existingURLTypes = (modResults.CFBundleURLTypes || []);
modResults.CFBundleURLTypes = addURLSchemeEntry(existingURLTypes, props.ios.smartechNudges.testDeviceURLName, props.ios.smartechNudges.testDeviceURLSchema);
return newConfig;
});
};
const addSmartechHeaderMod = (config, props) => {
return (0, config_plugins_1.withDangerousMod)(config, [
'ios',
async (config) => {
const { platformProjectRoot, projectName } = config.modRequest;
if (projectName && platformProjectRoot) {
const isSwift = await helper_1.Helper.Ios.isSwiftProject(platformProjectRoot, projectName);
if (isSwift) {
// For Swift projects, add imports to AppDelegate.swift
try {
const appDelegateSwiftPath = path_1.default.join(platformProjectRoot, projectName, 'AppDelegate.swift');
const appDelegateSwiftContents = await fs_1.promises.readFile(appDelegateSwiftPath, 'utf-8');
//console.log(`appdelegate content before is ${appDelegateSwiftContents}`);
console.log(`appdelegate path is ${appDelegateSwiftPath}`);
// Add Smartech import if not already present (check for exact import line)
const lines = appDelegateSwiftContents.split('\n');
const hasSmartechImport = lines.some(line => line.trim() === iosConstants_1.swiftImports.smartechImport);
if (!hasSmartechImport) {
let insertIndex = 0;
// Find the last import statement
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith('import ')) {
insertIndex = i + 1;
}
else if (lines[i].trim() !== '' && !lines[i].trim().startsWith('import ')) {
break;
}
}
// Insert the Smartech import
lines.splice(insertIndex, 0, iosConstants_1.swiftImports.smartechImport);
const modifiedContents = lines.join('\n');
//console.log(`appdelegate content is ${modifiedContents}`);
await fs_1.promises.writeFile(appDelegateSwiftPath, modifiedContents, 'utf-8');
console.log(`${iosConstants_1.swiftImports.smartechImport} added to AppDelegate.swift at line ${insertIndex + 1}`);
}
else {
console.log(`${iosConstants_1.swiftImports.smartechImport} is already added to AppDelegate.swift`);
}
}
catch (error) {
console.error('Error modifying AppDelegate.swift:', error);
}
}
else {
// For Objective-C projects (existing logic)
try {
const appDelegateHeaderPath = path_1.default.join(platformProjectRoot, projectName, iosConstants_1.appdelegateSnippet.fileName);
const appDelegateHeaderContents = await fs_1.promises.readFile(appDelegateHeaderPath, 'utf-8');
// Add Smartech header snipper if not already present.
if (!appDelegateHeaderContents.includes(iosConstants_1.appdelegateSnippet.smartechHeaderSnippet)) {
const modifiedAppDelegateHeaderContents = `${appDelegateHeaderContents}\n${iosConstants_1.appdelegateSnippet.smartechHeaderSnippet}`;
await fs_1.promises.writeFile(appDelegateHeaderPath, modifiedAppDelegateHeaderContents, 'utf-8');
}
else {
console.log(`${iosConstants_1.appdelegateSnippet.smartechHeaderSnippet} is already added.`);
}
}
catch (error) {
console.error('Error modifying AppDelegate.h:', error);
}
}
}
return config;
}
]);
};
const addSmartechHanseleHeaderMod = (config, props) => {
return (0, config_plugins_1.withDangerousMod)(config, [
'ios',
async (config) => {
const { platformProjectRoot, projectName } = config.modRequest;
if (platformProjectRoot && projectName) {
const isSwift = await helper_1.Helper.Ios.isSwiftProject(platformProjectRoot, projectName);
if (isSwift) {
// For Swift projects, add imports to AppDelegate.swift
try {
const appDelegateSwiftPath = path_1.default.join(platformProjectRoot, projectName, 'AppDelegate.swift');
// Re-read the file to get the current state (including any changes from previous functions)
const appDelegateSwiftContents = await fs_1.promises.readFile(appDelegateSwiftPath, 'utf-8');
// console.log(`appdelegate content hansel before is ${appDelegateSwiftContents}`);
// Add Hansel import if Hansel is enabled and not already present (check for exact import line)
const lines = appDelegateSwiftContents.split('\n');
const hasHanselImport = lines.some(line => line.trim() === iosConstants_1.swiftImports.hanselImport);
if (props.ios.smartechNudges.smartechNudgesEnabled && !hasHanselImport) {
let insertIndex = 0;
// Find the last import statement
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith('import ')) {
insertIndex = i + 1;
}
else if (lines[i].trim() !== '' && !lines[i].trim().startsWith('import ')) {
break;
}
}
// Insert the Hansel import
lines.splice(insertIndex, 0, iosConstants_1.swiftImports.hanselImport);
const modifiedContents = lines.join('\n');
// console.log(`appdelegate content hansel after is ${modifiedContents}`);
await fs_1.promises.writeFile(appDelegateSwiftPath, modifiedContents, 'utf-8');
console.log(`${iosConstants_1.swiftImports.hanselImport} added to AppDelegate.swift at line ${insertIndex + 1}`);
}
else {
console.log(`${iosConstants_1.swiftImports.hanselImport} is already added or SmartechNudges disabled: ${props.ios.smartechNudges.smartechNudgesEnabled}`);
}
}
catch (error) {
console.error('Error modifying AppDelegate.swift:', error);
}
}
else {
// For Objective-C projects (existing logic)
try {
const appDelegateHeaderPath = path_1.default.join(platformProjectRoot, projectName, iosConstants_1.appdelegateSnippet.fileName);
const appDelegateHeaderContents = await fs_1.promises.readFile(appDelegateHeaderPath, 'utf-8');
// Add Hansel header snippet if Hansel is enabled and not already present
if (props.ios.smartechNudges.smartechNudgesEnabled && !appDelegateHeaderContents.includes(iosConstants_1.appdelegateSnippet.hanselHeaderSnippet)) {
const modifiedAppDelegateHeaderContents = `${appDelegateHeaderContents}\n${iosConstants_1.appdelegateSnippet.hanselHeaderSnippet}`;
await fs_1.promises.writeFile(appDelegateHeaderPath, modifiedAppDelegateHeaderContents, 'utf-8');
}
else {
console.log(`${iosConstants_1.appdelegateSnippet.hanselHeaderSnippet} is already added or status of SmartechNudge: ${props.ios.smartechNudges.smartechNudgesEnabled}`);
}
}
catch (error) {
console.error('Error modifying AppDelegate.h:', error);
}
}
}
return config;
}
]);
};
// Set custom AppDelegate contents modifications
const setCustomAppDelegateContentsMod = (config, props) => {
return (0, config_plugins_1.withDangerousMod)(config, [
'ios',
async (config) => {
const { platformProjectRoot, projectName } = config.modRequest;
if (platformProjectRoot && projectName) {
const isSwift = await helper_1.Helper.Ios.isSwiftProject(platformProjectRoot, projectName);
if (isSwift) {
// Handle Swift AppDelegate
const appDelegateSwiftPath = path_1.default.join(platformProjectRoot, projectName, 'AppDelegate.swift');
try {
let contents = await fs_1.promises.readFile(appDelegateSwiftPath, 'utf-8');
contents = addSmartechInitCodeSwift(contents, props);
contents = addDeepLinkHandlerSwift(contents, props);
await fs_1.promises.writeFile(appDelegateSwiftPath, contents, 'utf-8');
console.log('Swift AppDelegate contents updated successfully');
}
catch (error) {
console.error('Error modifying AppDelegate.swift:', error);
}
}
else {
// Handle Objective-C AppDelegate (existing logic)
const appDelegatePath = await helper_1.Helper.Ios.getObjCAppDelegatePath(platformProjectRoot, projectName);
try {
let contents = await fs_1.promises.readFile(appDelegatePath, 'utf-8');
const smartechInitContent = addSmartechInitCode(contents, props);
const updatedContent = helper_1.Helper.Ios.addDeepLinkHandler(smartechInitContent, props);
await fs_1.promises.writeFile(appDelegatePath, updatedContent, 'utf-8');
console.log(`Objective-C AppDelegate contents updated successfully: ${appDelegatePath}`);
}
catch (error) {
console.error(`Error modifying AppDelegate file (${appDelegatePath}):`, error);
}
}
}
return config;
}
]);
};
// Helper function to modify AppDelegate contents
const addSmartechInitCode = (contents, props) => {
const lines = contents.split("\n");
const didLaunchIndex = lines.findIndex(line => iosConstants_1.smartechBaseSnippet.regexPattern.test(line));
if (didLaunchIndex === -1) {
return contents;
}
// Prepare the lines to insert
const sdkLines = [
iosConstants_1.smartechBaseSnippet.smartechInit,
...(props.ios.isLogEnabled ? [iosConstants_1.smartechBaseSnippet.debugLevel] : []),
iosConstants_1.smartechBaseSnippet.trackAppInstallUpdateBySmartech,
...((props.ios.smartechNudges.smartechNudgesEnabled && props.ios.smartechNudges.isLogEnabled) ? [iosConstants_1.smartechBaseSnippet.hanselLogSnippet] : []),
];
// Add the snippets before and after the `didFinishLaunching` index
const resultLines = [
...lines.slice(0, didLaunchIndex + 2),
...sdkLines,
...lines.slice(didLaunchIndex + 2),
];
return resultLines.join("\n");
};
// Helper function to modify Swift AppDelegate contents
const addSmartechInitCodeSwift = (contents, props) => {
const lines = contents.split("\n");
// Find didFinishLaunchingWithOptions method by looking for the specific method name
let didLaunchIndex = -1;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Look for func application and then check if didFinishLaunchingWithOptions appears in the next few lines
if (iosConstants_1.smartechBaseSwiftSnippet.didFinishLaunchingRegex.test(line)) {
// Check the next 5 lines for didFinishLaunchingWithOptions
for (let j = i; j < Math.min(i + 5, lines.length); j++) {
if (lines[j].includes('didFinishLaunchingWithOptions')) {
didLaunchIndex = i;
break;
}
}
if (didLaunchIndex !== -1)
break;
}
}
if (didLaunchIndex === -1) {
console.log('Could not find didFinishLaunchingWithOptions method in Swift AppDelegate');
return contents;
}
// Find the opening brace of the method
let methodStartIndex = didLaunchIndex;
for (let i = didLaunchIndex; i < lines.length; i++) {
if (lines[i].includes('{')) {
methodStartIndex = i;
break;
}
}
// Prepare the lines to insert
const sdkLines = [
` ${iosConstants_1.smartechBaseSwiftSnippet.smartechInit}`,
...(props.ios.isLogEnabled ? [` ${iosConstants_1.smartechBaseSwiftSnippet.debugLevel}`] : []),
` ${iosConstants_1.smartechBaseSwiftSnippet.trackAppInstallUpdateBySmartech}`,
...((props.ios.smartechNudges.smartechNudgesEnabled && props.ios.smartechNudges.isLogEnabled) ? [` ${iosConstants_1.smartechBaseSwiftSnippet.hanselLogSnippet}`] : []),
];
// Add the snippets after the method opening brace
const resultLines = [
...lines.slice(0, methodStartIndex + 1),
...sdkLines,
...lines.slice(methodStartIndex + 1),
];
console.log('Swift SDK initialization code added to didFinishLaunchingWithOptions');
return resultLines.join("\n");
};
// Helper function to add Swift deeplink handler
const addDeepLinkHandlerSwift = (contents, props) => {
const lines = contents.split("\n");
// Find the end of the main AppDelegate class (before the last closing brace, but not the ReactNativeDelegate class)
let classEndIndex = -1;
let insideAppDelegate = false;
let braceCount = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
// Look for the AppDelegate class declaration
if (line.includes('class') && line.includes('AppDelegate') && line.includes(':')) {
insideAppDelegate = true;
braceCount = 0;
}
if (insideAppDelegate) {
// Count braces to find the end of the AppDelegate class
const openBraces = (line.match(/\{/g) || []).length;
const closeBraces = (line.match(/\}/g) || []).length;
braceCount += openBraces - closeBraces;
// When we reach the closing brace of AppDelegate class
if (braceCount === 0 && line.includes('}') && openBraces === 0) {
classEndIndex = i;
break;
}
}
}
if (classEndIndex === -1) {
console.log('Could not find AppDelegate class end in Swift file');
return contents;
}
const deepLinkHandlerLines = (0, iosConstants_1.deepLinkHandlerSwiftSnippet)(props.deepLinkDelay);
const resultLines = [
...lines.slice(0, classEndIndex),
deepLinkHandlerLines,
...lines.slice(classEndIndex),
];
return resultLines.join("\n");
};
// Helper function to modify Swift openURL method
const modifySwiftOpenURLMethod = (contents) => {
const swiftCodeBlock = `let handleBySmartech = Smartech.sharedInstance().application(app, open: url, options: options)
if !handleBySmartech {
return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)
}
return true`;
if (contents.includes("open url:")) {
const modifiedContents = contents.replace("return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options)", swiftCodeBlock);
return modifiedContents;
}
console.log('Could not find Swift openURL method to modify');
return contents;
};
// Set custom AppDelegate contents modifications
const modifyAppDelegateWithLinker = (config, props) => {
const addTestDeviceForSmartech = props.ios.addTestDevice ?? false;
const addTestDeviceForHansel = props.ios.smartechNudges.smartechNudgesEnabled &&
(props.ios.smartechNudges.addTestDevice ?? false);
if (!addTestDeviceForSmartech && !addTestDeviceForHansel) {
return config;
}
return (0, config_plugins_1.withDangerousMod)(config, [
'ios',
async (config) => {
const { platformProjectRoot, projectName } = config.modRequest;
if (platformProjectRoot && projectName) {
const isSwift = await helper_1.Helper.Ios.isSwiftProject(platformProjectRoot, projectName);
if (isSwift) {
// Handle Swift AppDelegate
const appDelegateSwiftPath = path_1.default.join(platformProjectRoot, projectName, 'AppDelegate.swift');
try {
let contents = await fs_1.promises.readFile(appDelegateSwiftPath, 'utf-8');
contents = modifySwiftOpenURLMethod(contents);
await fs_1.promises.writeFile(appDelegateSwiftPath, contents, 'utf-8');
console.log('Swift AppDelegate openURL method updated successfully');
}
catch (error) {
console.error('Error modifying Swift AppDelegate openURL method:', error);
}
}
else {
// Handle Objective-C AppDelegate (existing logic)
const appDelegatePath = await helper_1.Helper.Ios.getObjCAppDelegatePath(platformProjectRoot, projectName);
try {
let contents = await fs_1.promises.readFile(appDelegatePath, 'utf-8');
const codeBlock = `BOOL handleBySmartech = [[Smartech sharedInstance] application:application openURL:url options:options];
if(!handleBySmartech) {
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}
return YES;`;
if (contents.includes("openURL:")) {
const modifiedContents = contents.replace("return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];", `${codeBlock}`);
await fs_1.promises.writeFile(appDelegatePath, modifiedContents, 'utf-8');
}
}
catch (error) {
console.error('Error modifying Objective-C AppDelegate openURL method:', error);
}
}
}
return config;
}
]);
};
const withNetcoreiOS = (config, props) => {
config = modifyEntitlementsPlist(config, props);
config = modifyInfoPlist(config, props);
config = addSmartechURLScheme(config, props);
config = addHanselURLScheme(config, props);
config = addSmartechHeaderMod(config, props);
config = addSmartechHanseleHeaderMod(config, props);
config = setCustomAppDelegateContentsMod(config, props);
config = modifyAppDelegateWithLinker(config, props);
return config;
};
exports.withNetcoreiOS = withNetcoreiOS;