UNPKG

react-native-expo-braintree

Version:

React native and expo wrapper around braintree sdk fro android and ios

212 lines (194 loc) 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withVenmoScheme = exports.withExpoBraintreePlist = exports.withExpoBraintreeAppDelegate = exports.withBraintreeWrapperFile = exports.modifyAppDelegateSwift = exports.modifyAppDelegateObjectiveC = void 0; var _configPlugins = require("@expo/config-plugins"); var _eol = _interopRequireDefault(require("eol")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /* eslint-disable no-bitwise */ /* * Mods for Info.plist */ const withExpoBraintreePlist = expoConfig => { return (0, _configPlugins.withInfoPlist)(expoConfig, config => { const bundleIdentifier = config.ios?.bundleIdentifier ?? ''; const bundleIdentifierWithBraintreeSchema = `${bundleIdentifier}.braintree`; const bundleUrlTypes = config.modResults.CFBundleURLTypes ?? []; // Check if an entry with the specific Braintree URL scheme already exists const isBraintreeEntryNotExist = !bundleUrlTypes.find(urlType => { return urlType.CFBundleURLSchemes?.includes(bundleIdentifierWithBraintreeSchema); }); // If Braintree entry doesn't exist, add a new one if (isBraintreeEntryNotExist) { bundleUrlTypes.push({ CFBundleURLSchemes: [bundleIdentifierWithBraintreeSchema] }); } // Assign the modified bundleUrlTypes back to the config config.modResults.CFBundleURLTypes = bundleUrlTypes; return config; }); }; /* * Add allowlist Venmo URL scheme * @see https://developer.paypal.com/braintree/docs/guides/venmo/client-side/ios/v6#allowlist-venmo-url-scheme */ exports.withExpoBraintreePlist = withExpoBraintreePlist; const withVenmoScheme = expoConfig => { return (0, _configPlugins.withInfoPlist)(expoConfig, config => { // Ensure LSApplicationQueriesSchemes exists in Info.plist config.modResults.LSApplicationQueriesSchemes = config.modResults.LSApplicationQueriesSchemes || []; // Hardcoded scheme for Venmo const venmoScheme = 'com.venmo.touch.v2'; // Add the Venmo scheme to the LSApplicationQueriesSchemes array if not already present if (!config.modResults.LSApplicationQueriesSchemes.includes(venmoScheme)) { config.modResults.LSApplicationQueriesSchemes.push(venmoScheme); } return config; }); }; /* * Mods for Info.plist */ /** * Mods for AppDelegate.swift React Native above 0.77.x and Expo above 53 */ exports.withVenmoScheme = withVenmoScheme; const modifyAppDelegateSwift = config => { const appDelegate = config.modResults; let contents = _eol.default.split(appDelegate.contents); // Step 1 Add method to properly handle openUrl method in AppDelegate.m // func application( // _ application: UIApplication, // open url: URL, // options: [UIApplication.OpenURLOptionsKey : Any] = [:] // ) -> Bool { // if url.scheme?.localizedCaseInsensitiveCompare( // ExpoBraintreeConfig.paymentURLScheme // ) == .orderedSame { // return ExpoBraintreeConfig.handleUrl(url: url) // } // return RCTLinkingManager.application( // application, // open: url, // options: options // ) // } // Step 1.1 // We need to try to find if in AppDelegate.swift there is already an application method to handle url // we also need to be sure that we do not break other plugins as well const openUrlIdentifier = `options: [UIApplication.OpenURLOptionsKey: Any] = [:]`; const expoBraintreeConfigHandleUrl = `return ExpoBraintreeConfig.handleUrl(url: url)`; const expoBraintreeOpenUrlLines = [` // @generated by react-native-expo-braintree (DO NOT MODIFY)`, ` if url.scheme?.localizedCaseInsensitiveCompare(`, ` ExpoBraintreeConfig.paymentURLScheme`, ` ) == .orderedSame {`, ` ${expoBraintreeConfigHandleUrl}`, ` }`, ` // @generated by react-native-expo-braintree (DO NOT MODIFY)`]; const openUrlIdentifierElementIndex = contents.findIndex(content => content.includes(openUrlIdentifier)); // Step 2 If openUrlIdentifierElementIndex exist in AppDelegate.swift then we only need to add expoBraintreeOpenUrlLines at the top of that method /* eslint-disable no-extra-boolean-cast */ if (!!~openUrlIdentifierElementIndex) { contents.splice( // We are adding +1 to the index to insert content after ') -> Bool {' block openUrlIdentifierElementIndex + 2, 0, ...expoBraintreeOpenUrlLines); } // Step 3 If openUrlIdentifierElementIndex do not exist in AppDelegate.swift add a warning that something went wrong else { _configPlugins.WarningAggregator.addWarningIOS('withExpoBraintree', `Unable to find "options: [UIApplication.OpenURLOptionsKey: Any] = [:]" in AppDelegate.swift, automatic changes not applied expo-braintree might not working as expected`); } const expoBraintreeConfigHandleUrlElementIndex = contents.findIndex(content => content.includes(expoBraintreeConfigHandleUrl)); // If openUrlMethodElementIndex exist in AppDelegate.mm and expoBraintreeOpenUrlLineIndex do not exist if (!~expoBraintreeConfigHandleUrlElementIndex) { _configPlugins.WarningAggregator.addWarningIOS('withExpoBraintree', `Unable to find "return ExpoBraintreeConfig.handleUrl(url: url)" in AppDelegate.swift, automatic changes not applied expo-braintree might not working as expected`); } return contents; }; /** * Mods for AppDelegate.swift */ /** * Mods for AppDelegate.mm / AppDelegate.m React Native below 0.77.x and Expo below 53 */ exports.modifyAppDelegateSwift = modifyAppDelegateSwift; const modifyAppDelegateObjectiveC = (config, xCodeProjectAppName) => { if (!xCodeProjectAppName) { _configPlugins.WarningAggregator.addWarningIOS('withExpoBraintree', `xCodeProjectAppName props not provided but in case of using plugin in objective c world it is required`); } const appDelegate = config.modResults; let contents = _eol.default.split(appDelegate.contents); // Step 1 Edit Import part // Editing import part for -swift.h file to be able to use Braintree const importSwiftHeaderFileContent = `#import "${xCodeProjectAppName}-Swift.h"`; const importSwiftHeaderFileIndex = contents.findIndex(content => content.includes(importSwiftHeaderFileContent)); // If importSwiftHeaderFileContent do not exist in AppDelegate.mm if (!~importSwiftHeaderFileIndex) { contents = [importSwiftHeaderFileContent, ...contents]; } const importExpoModulesSwiftHeader = `#import "ExpoModulesCore-Swift.h"`; const importExpoModulesSwiftHeaderFileIndex = contents.findIndex(content => content.includes(importExpoModulesSwiftHeader)); // If importExpoModulesSwiftHeader do not exist in AppDelegate.mm if (!~importExpoModulesSwiftHeaderFileIndex) { contents = [importExpoModulesSwiftHeader, ...contents]; } // Step 2 Add method to properly handle openUrl method in AppDelegate.m const openUrlMethod = '- (BOOL)application:(UIApplication *)application openURL'; const expoBraintreeOpenUrlLines = [' if ([url.scheme localizedCaseInsensitiveCompare:[BraintreeExpoConfig getPaymentUrlScheme]] == NSOrderedSame) {', ' return [BraintreeExpoConfig handleUrl:url];', ' }']; const openUrlMethodElementIndex = contents.findIndex(content => content.includes(openUrlMethod)); const expoBraintreeOpenUrlLineIndex = contents.findIndex(content => content.includes(expoBraintreeOpenUrlLines?.[0] ?? '')); // If openUrlMethodElementIndex exist in AppDelegate.mm and expoBraintreeOpenUrlLineIndex do not exist if (!~expoBraintreeOpenUrlLineIndex && !!~openUrlMethodElementIndex) { contents.splice( // We are adding +1 to the index to insert content after '{' block openUrlMethodElementIndex + 1, 0, ...expoBraintreeOpenUrlLines); } return contents; }; /** * Mods for AppDelegate.mm */ exports.modifyAppDelegateObjectiveC = modifyAppDelegateObjectiveC; const withExpoBraintreeAppDelegate = (expoConfig, { xCodeProjectAppName }) => { let appDelegateLanguage = null; return (0, _configPlugins.withAppDelegate)(expoConfig, config => { appDelegateLanguage = config.modResults.language; switch (appDelegateLanguage) { case 'objc': case 'objcpp': const resultObjectiVeC = modifyAppDelegateObjectiveC(config, xCodeProjectAppName); config.modResults.contents = resultObjectiVeC.join('\n'); return config; case 'swift': const resultSwift = modifyAppDelegateSwift(config); config.modResults.contents = resultSwift.join('\n'); return config; default: _configPlugins.WarningAggregator.addWarningIOS('withExpoBraintree', `${appDelegateLanguage} AppDelegate file is not supported yet`); return config; } }); }; // Add a new wrapper Swift file to the Xcode project for Swift compatibility. exports.withExpoBraintreeAppDelegate = withExpoBraintreeAppDelegate; const withBraintreeWrapperFile = (config, { appDelegateLanguage }) => { const braintreeWrapperObjectiveC = ['import Braintree', 'import Foundation', '', '@objc public class BraintreeExpoConfig: NSObject {', '', '@objc(getPaymentUrlScheme)', 'public static func getPaymentUrlScheme() -> String {', ' let bundleIdentifier = Bundle.main.bundleIdentifier ?? ""', ' return bundleIdentifier + ".braintree"', '}', '', '@objc(handleUrl:)', 'public static func handleUrl(url: URL) -> Bool {', ' return BTAppContextSwitcher.sharedInstance.handleOpen(url)', '}', '}']; const braintreeWrapperSwift = ['import Braintree', 'import Foundation', '', 'public final class ExpoBraintreeConfig {', '', ' private init() {}', '', ' public static var paymentURLScheme: String {', ' let bundleIdentifier = Bundle.main.bundleIdentifier ?? ""', ' return bundleIdentifier + ".braintree"', ' }', '', ' public static func handleUrl(url: URL) -> Bool {', ' return BTAppContextSwitcher.sharedInstance.handleOpen(url)', ' }', '}']; switch (appDelegateLanguage) { case 'objc': case 'objcpp': return _configPlugins.IOSConfig.XcodeProjectFile.withBuildSourceFile(config, { filePath: 'ExpoBraintreeConfig.swift', contents: braintreeWrapperObjectiveC.join('\n') }); case 'swift': return _configPlugins.IOSConfig.XcodeProjectFile.withBuildSourceFile(config, { filePath: 'ExpoBraintreeConfig.swift', contents: braintreeWrapperSwift.join('\n') }); default: _configPlugins.WarningAggregator.addWarningIOS('withExpoBraintree', `${appDelegateLanguage} AppDelegate file is not supported yet`); return config; } }; exports.withBraintreeWrapperFile = withBraintreeWrapperFile; //# sourceMappingURL=withExpoBraintree.ios.js.map