react-native-ssl-manager 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +319 -58
- package/android/build.gradle +23 -1
- package/android/src/main/java/com/usesslpinning/SslPinningFactory.kt +94 -0
- package/android/src/main/java/com/usesslpinning/UseSslPinningModuleImpl.kt +34 -0
- package/android/src/newarch/com/usesslpinning/UseSslPinningModule.kt +26 -0
- package/android/src/newarch/com/usesslpinning/UseSslPinningPackage.kt +36 -0
- package/android/src/oldarch/com/usesslpinning/UseSslPinningModule.kt +32 -0
- package/android/src/{main/java → oldarch}/com/usesslpinning/UseSslPinningPackage.kt +0 -1
- package/android/ssl-pinning-setup.gradle +148 -0
- package/app.plugin.js +293 -0
- package/expo-module.config.json +10 -0
- package/ios/SharedLogic.swift +247 -0
- package/ios/UseSslPinning.h +5 -0
- package/ios/{UseSslPinning.mm → UseSslPinningModule.mm} +9 -6
- package/ios/UseSslPinningModule.swift +65 -0
- package/lib/NativeUseSslPinning.d.ts +8 -0
- package/lib/NativeUseSslPinning.d.ts.map +1 -0
- package/lib/NativeUseSslPinning.js +4 -0
- package/lib/UseSslPinning.types.d.ts +17 -0
- package/lib/UseSslPinning.types.d.ts.map +1 -0
- package/lib/UseSslPinning.types.js +2 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +58 -0
- package/package.json +83 -39
- package/react-native-ssl-manager.podspec +87 -38
- package/react-native.config.js +34 -0
- package/scripts/build.sh +52 -0
- package/src/NativeUseSslPinning.ts +9 -0
- package/src/UseSslPinning.types.ts +17 -0
- package/src/index.tsx +53 -33
- package/android/src/main/java/com/usesslpinning/UseSslPinningFactory.kt +0 -50
- package/android/src/main/java/com/usesslpinning/UseSslPinningModule.kt +0 -45
- package/ios/UseSslPinning-Bridging-Header.h +0 -2
- package/ios/UseSslPinning.swift +0 -169
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package com.usesslpinning
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
import com.facebook.react.bridge.Promise
|
|
8
|
+
import com.facebook.react.modules.network.OkHttpClientProvider
|
|
9
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
10
|
+
|
|
11
|
+
@ReactModule(name = UseSslPinningModuleImpl.NAME)
|
|
12
|
+
class UseSslPinningModule(reactContext: ReactApplicationContext) :
|
|
13
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
14
|
+
|
|
15
|
+
init {
|
|
16
|
+
UseSslPinningModuleImpl.initialize(reactContext)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun getName(): String {
|
|
20
|
+
return UseSslPinningModuleImpl.NAME
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@ReactMethod
|
|
24
|
+
fun setUseSSLPinning(usePinning: Boolean, promise: Promise) {
|
|
25
|
+
UseSslPinningModuleImpl.setUseSSLPinning(reactApplicationContext, usePinning, promise)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@ReactMethod
|
|
29
|
+
fun getUseSSLPinning(promise: Promise) {
|
|
30
|
+
UseSslPinningModuleImpl.getUseSSLPinning(reactApplicationContext, promise)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -5,7 +5,6 @@ import com.facebook.react.bridge.NativeModule
|
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
6
|
import com.facebook.react.uimanager.ViewManager
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
class UseSslPinningPackage : ReactPackage {
|
|
10
9
|
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
11
10
|
return listOf(UseSslPinningModule(reactContext))
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
def findSslConfigFile() {
|
|
2
|
+
def candidates = [
|
|
3
|
+
file("${project.rootDir}/../ssl_config.json"), // repo root (android/ là thư mục con)
|
|
4
|
+
file("${project.rootDir}/ssl_config.json"), // android root
|
|
5
|
+
file("${projectDir}/../../ssl_config.json"), // monorepo fallback
|
|
6
|
+
file("${projectDir}/../ssl_config.json")
|
|
7
|
+
]
|
|
8
|
+
for (f in candidates) {
|
|
9
|
+
if (f.exists()) return f
|
|
10
|
+
}
|
|
11
|
+
return null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
def ensureAssetsDir() {
|
|
15
|
+
def d = file("${projectDir}/src/main/assets")
|
|
16
|
+
if (!d.exists()) d.mkdirs()
|
|
17
|
+
return d
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def assetsDir = file("${projectDir}/src/main/assets")
|
|
21
|
+
def destFile = file("${projectDir}/src/main/assets/ssl_config.json")
|
|
22
|
+
|
|
23
|
+
plugins.withId('com.android.application') {
|
|
24
|
+
|
|
25
|
+
// ===== AGP 7/8: androidComponents DSL =====
|
|
26
|
+
if (project.extensions.findByName("androidComponents") != null) {
|
|
27
|
+
androidComponents {
|
|
28
|
+
onVariants(selector().all()) { variant -> // <-- Sửa chỗ này
|
|
29
|
+
def vName = variant.name
|
|
30
|
+
def vNameCap = vName.substring(0,1).toUpperCase() + vName.substring(1)
|
|
31
|
+
def taskName = "copySslConfig${vNameCap}"
|
|
32
|
+
|
|
33
|
+
tasks.register(taskName, Copy) {
|
|
34
|
+
group = "SSL Pinning"
|
|
35
|
+
description = "Copy ssl_config.json to assets for ${vName}"
|
|
36
|
+
|
|
37
|
+
def sourceFile = findSslConfigFile()
|
|
38
|
+
|
|
39
|
+
onlyIf {
|
|
40
|
+
if (sourceFile) {
|
|
41
|
+
println "📋 SSL Config found: ${sourceFile.absolutePath}"
|
|
42
|
+
true
|
|
43
|
+
} else {
|
|
44
|
+
println "⚠️ SSL Config not found in expected locations"
|
|
45
|
+
false
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
doFirst {
|
|
50
|
+
ensureAssetsDir()
|
|
51
|
+
println "🔄 Copying SSL config for variant: ${vName}"
|
|
52
|
+
println "📂 To: ${assetsDir}"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
from { sourceFile }
|
|
56
|
+
into assetsDir
|
|
57
|
+
|
|
58
|
+
doLast {
|
|
59
|
+
if (destFile.exists()) {
|
|
60
|
+
println "✅ SSL config copied: ${destFile} (${destFile.length()} bytes)"
|
|
61
|
+
} else {
|
|
62
|
+
println "❌ SSL config copy failed"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Hook chắc chắn cho assemble/install/mergeAssets
|
|
68
|
+
tasks.matching { it.name == "merge${vNameCap}Assets" }.configureEach { dependsOn taskName }
|
|
69
|
+
tasks.matching { it.name == "install${vNameCap}" }.configureEach { dependsOn taskName }
|
|
70
|
+
tasks.matching { it.name == "assemble${vNameCap}" }.configureEach { dependsOn taskName }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
} else {
|
|
75
|
+
// ===== Fallback: API cũ applicationVariants =====
|
|
76
|
+
afterEvaluate {
|
|
77
|
+
android.applicationVariants.all { variant ->
|
|
78
|
+
def bt = variant.buildType.name
|
|
79
|
+
def fl = variant.flavorName ?: ""
|
|
80
|
+
def vNameCap = (fl ? "${fl.capitalize()}${bt.capitalize()}" : bt.capitalize())
|
|
81
|
+
def taskName = "copySslConfig${vNameCap}"
|
|
82
|
+
|
|
83
|
+
def copyTask = tasks.create(taskName, Copy) {
|
|
84
|
+
group = "SSL Pinning"
|
|
85
|
+
description = "Copy ssl_config.json to assets for ${vNameCap}"
|
|
86
|
+
|
|
87
|
+
def sourceFile = findSslConfigFile()
|
|
88
|
+
|
|
89
|
+
onlyIf {
|
|
90
|
+
if (sourceFile) {
|
|
91
|
+
println "📋 SSL Config found: ${sourceFile.absolutePath}"
|
|
92
|
+
true
|
|
93
|
+
} else {
|
|
94
|
+
println "⚠️ SSL Config not found in expected locations"
|
|
95
|
+
false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
doFirst {
|
|
100
|
+
ensureAssetsDir()
|
|
101
|
+
println "🔄 Copying SSL config for variant: ${vNameCap}"
|
|
102
|
+
println "📂 To: ${assetsDir}"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
from { sourceFile }
|
|
106
|
+
into assetsDir
|
|
107
|
+
|
|
108
|
+
doLast {
|
|
109
|
+
if (destFile.exists()) {
|
|
110
|
+
println "✅ SSL config copied: ${destFile} (${destFile.length()} bytes)"
|
|
111
|
+
} else {
|
|
112
|
+
println "❌ SSL config copy failed"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
if (variant.hasProperty("mergeAssetsProvider")) {
|
|
119
|
+
variant.mergeAssetsProvider.configure { dependsOn copyTask }
|
|
120
|
+
} else {
|
|
121
|
+
tasks.named("merge${vNameCap}Assets").configure { dependsOn copyTask }
|
|
122
|
+
}
|
|
123
|
+
} catch (ignored) { }
|
|
124
|
+
try { tasks.named("install${vNameCap}").configure { dependsOn copyTask } } catch (ignored) { }
|
|
125
|
+
try { tasks.named("assemble${vNameCap}").configure { dependsOn copyTask } } catch (ignored) { }
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ===== Utility =====
|
|
131
|
+
tasks.register("checkSslConfig") {
|
|
132
|
+
group = "SSL Pinning"
|
|
133
|
+
description = "Check SSL config file status"
|
|
134
|
+
doLast {
|
|
135
|
+
def source = findSslConfigFile()
|
|
136
|
+
println "\n📋 SSL Pinning Configuration Status:"
|
|
137
|
+
println " Source config: " + (source ? "✅ Found at ${source.absolutePath}" : "❌ Not found")
|
|
138
|
+
println " Assets config: " + (destFile.exists() ? "✅ Found at ${destFile.absolutePath}" : "❌ Not found")
|
|
139
|
+
if (!source) {
|
|
140
|
+
println "💡 Create ssl_config.json tại repo root (ngang 'android/') hoặc trong 'android/'."
|
|
141
|
+
} else if (!destFile.exists()) {
|
|
142
|
+
println "💡 Run: ./gradlew copySslConfigDebug (hoặc biến thể tương ứng)"
|
|
143
|
+
} else {
|
|
144
|
+
println "✅ SSL config is properly setup"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
const {
|
|
2
|
+
withInfoPlist,
|
|
3
|
+
withDangerousMod,
|
|
4
|
+
withXcodeProject,
|
|
5
|
+
withAndroidManifest,
|
|
6
|
+
withMainApplication,
|
|
7
|
+
} = require('@expo/config-plugins');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Expo Config Plugin for react-native-ssl-manager
|
|
13
|
+
* Automatically configures SSL pinning for Expo projects
|
|
14
|
+
*/
|
|
15
|
+
function withSslManager(config, options = {}) {
|
|
16
|
+
const {
|
|
17
|
+
enableAndroid = true,
|
|
18
|
+
enableIOS = true,
|
|
19
|
+
sslConfigPath = 'ssl_config.json',
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
// Add Android configuration
|
|
23
|
+
if (enableAndroid) {
|
|
24
|
+
config = withAndroidSslPinning(config);
|
|
25
|
+
config = withAndroidMainApplication(config);
|
|
26
|
+
config = withAndroidAssets(config, { sslConfigPath });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Add iOS configuration
|
|
30
|
+
if (enableIOS) {
|
|
31
|
+
config = withIOSSslPinning(config);
|
|
32
|
+
config = withIosAssets(config, { sslConfigPath });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return config;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Configure Android SSL pinning
|
|
40
|
+
*/
|
|
41
|
+
function withAndroidSslPinning(config) {
|
|
42
|
+
return withAndroidManifest(config, (config) => {
|
|
43
|
+
const manifest = config.modResults;
|
|
44
|
+
|
|
45
|
+
// Add required permissions
|
|
46
|
+
if (!manifest.manifest['uses-permission']) {
|
|
47
|
+
manifest.manifest['uses-permission'] = [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const permissions = Array.isArray(manifest.manifest['uses-permission'])
|
|
51
|
+
? manifest.manifest['uses-permission']
|
|
52
|
+
: [manifest.manifest['uses-permission']];
|
|
53
|
+
|
|
54
|
+
// Add INTERNET permission if not exists
|
|
55
|
+
if (
|
|
56
|
+
!permissions.find(
|
|
57
|
+
(p) => p.$['android:name'] === 'android.permission.INTERNET'
|
|
58
|
+
)
|
|
59
|
+
) {
|
|
60
|
+
permissions.push({
|
|
61
|
+
$: {
|
|
62
|
+
'android:name': 'android.permission.INTERNET',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
manifest.manifest['uses-permission'] = permissions;
|
|
68
|
+
return config;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Configure Android MainApplication - No longer needed as autolinking handles package registration
|
|
74
|
+
* Keeping function for backward compatibility but removing auto-registration to avoid duplicates
|
|
75
|
+
*/
|
|
76
|
+
function withAndroidMainApplication(config) {
|
|
77
|
+
// No longer auto-register package - let autolinking handle it
|
|
78
|
+
// This prevents duplicate module registration errors
|
|
79
|
+
return config;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Auto-copy SSL config to Android assets
|
|
84
|
+
*/
|
|
85
|
+
function withAndroidAssets(config, options) {
|
|
86
|
+
return withDangerousMod(config, [
|
|
87
|
+
'android',
|
|
88
|
+
async (config) => {
|
|
89
|
+
const { sslConfigPath = 'ssl_config.json' } = options;
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
93
|
+
const sourceConfigPath = path.resolve(projectRoot, sslConfigPath);
|
|
94
|
+
|
|
95
|
+
if (fs.existsSync(sourceConfigPath)) {
|
|
96
|
+
const assetsDir = path.join(
|
|
97
|
+
config.modRequest.platformProjectRoot,
|
|
98
|
+
'app/src/main/assets'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Create assets directory if it doesn't exist
|
|
102
|
+
if (!fs.existsSync(assetsDir)) {
|
|
103
|
+
fs.mkdirSync(assetsDir, { recursive: true });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Copy SSL config to assets
|
|
107
|
+
const targetPath = path.join(assetsDir, 'ssl_config.json');
|
|
108
|
+
fs.copyFileSync(sourceConfigPath, targetPath);
|
|
109
|
+
} else {
|
|
110
|
+
console.warn(`⚠️ SSL config file not found at: ${sourceConfigPath}`);
|
|
111
|
+
console.warn(
|
|
112
|
+
'💡 Place ssl_config.json in your project root for auto-setup'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.warn('⚠️ Failed to auto-copy SSL config to assets:', error);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return config;
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Configure iOS SSL pinning - No Info.plist modification needed
|
|
126
|
+
* SSL pinning is handled by SharedLogic.swift at runtime
|
|
127
|
+
*/
|
|
128
|
+
function withIOSSslPinning(config) {
|
|
129
|
+
// No Info.plist modifications needed
|
|
130
|
+
// SSL pinning is initialized at runtime by SharedLogic.swift
|
|
131
|
+
|
|
132
|
+
return config;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Auto-copy SSL config to iOS bundle resources and add to Xcode project
|
|
137
|
+
*/
|
|
138
|
+
function withIosAssets(config, options) {
|
|
139
|
+
// First copy the file
|
|
140
|
+
config = withDangerousMod(config, [
|
|
141
|
+
'ios',
|
|
142
|
+
async (config) => {
|
|
143
|
+
const { sslConfigPath = 'ssl_config.json' } = options;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
147
|
+
const sourceConfigPath = path.resolve(projectRoot, sslConfigPath);
|
|
148
|
+
|
|
149
|
+
if (fs.existsSync(sourceConfigPath)) {
|
|
150
|
+
// Create ios directory if it doesn't exist
|
|
151
|
+
const iosDir = path.join(projectRoot, 'ios');
|
|
152
|
+
if (!fs.existsSync(iosDir)) {
|
|
153
|
+
fs.mkdirSync(iosDir, { recursive: true });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Copy ssl_config.json to ios directory
|
|
157
|
+
const targetConfigPath = path.join(iosDir, 'ssl_config.json');
|
|
158
|
+
fs.copyFileSync(sourceConfigPath, targetConfigPath);
|
|
159
|
+
|
|
160
|
+
// Also copy to app bundle directory for Xcode project
|
|
161
|
+
const appBundleDir = path.join(iosDir, config.modRequest.projectName);
|
|
162
|
+
const appBundleConfigPath = path.join(
|
|
163
|
+
appBundleDir,
|
|
164
|
+
'ssl_config.json'
|
|
165
|
+
);
|
|
166
|
+
if (fs.existsSync(appBundleDir)) {
|
|
167
|
+
fs.copyFileSync(sourceConfigPath, appBundleConfigPath);
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
console.warn(`⚠️ SSL config file not found at: ${sourceConfigPath}`);
|
|
171
|
+
console.warn(
|
|
172
|
+
'💡 Place ssl_config.json in your project root for auto-setup'
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.warn('⚠️ Failed to copy SSL config:', error);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return config;
|
|
180
|
+
},
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
// Add to Xcode project programmatically - run in same withDangerousMod as file copy
|
|
184
|
+
config = withDangerousMod(config, [
|
|
185
|
+
'ios',
|
|
186
|
+
async (config) => {
|
|
187
|
+
// First ensure file is copied to app bundle directory
|
|
188
|
+
const projectName = config.modRequest.projectName || 'exampleexpo';
|
|
189
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
190
|
+
const sourceConfigPath = path.resolve(projectRoot, 'ssl_config.json');
|
|
191
|
+
const appBundleDir = path.join(
|
|
192
|
+
config.modRequest.platformProjectRoot,
|
|
193
|
+
projectName
|
|
194
|
+
);
|
|
195
|
+
const appBundleConfigPath = path.join(appBundleDir, 'ssl_config.json');
|
|
196
|
+
|
|
197
|
+
// Ensure SSL config is copied to app bundle directory
|
|
198
|
+
if (fs.existsSync(sourceConfigPath) && fs.existsSync(appBundleDir)) {
|
|
199
|
+
fs.copyFileSync(sourceConfigPath, appBundleConfigPath);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const projectPath = path.join(
|
|
204
|
+
config.modRequest.platformProjectRoot,
|
|
205
|
+
`${projectName}.xcodeproj/project.pbxproj`
|
|
206
|
+
);
|
|
207
|
+
const sslConfigPath = appBundleConfigPath;
|
|
208
|
+
|
|
209
|
+
if (!fs.existsSync(projectPath) || !fs.existsSync(sslConfigPath)) {
|
|
210
|
+
console.warn(
|
|
211
|
+
'⚠️ Xcode project or SSL config not found, skipping automatic addition'
|
|
212
|
+
);
|
|
213
|
+
return config;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let projectContent = fs.readFileSync(projectPath, 'utf8');
|
|
217
|
+
|
|
218
|
+
// Check if already added
|
|
219
|
+
if (projectContent.includes('ssl_config.json')) {
|
|
220
|
+
return config;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Generate unique IDs for the file
|
|
224
|
+
const fileRefId =
|
|
225
|
+
'SSL' + Math.random().toString(36).substr(2, 24).toUpperCase();
|
|
226
|
+
const buildFileId =
|
|
227
|
+
'SSL' + Math.random().toString(36).substr(2, 24).toUpperCase();
|
|
228
|
+
|
|
229
|
+
// Add file reference
|
|
230
|
+
const fileRefEntry = `\t\t${fileRefId} /* ssl_config.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ssl_config.json; sourceTree = "<group>"; };`;
|
|
231
|
+
projectContent = projectContent.replace(
|
|
232
|
+
'/* End PBXFileReference section */',
|
|
233
|
+
fileRefEntry + '\n\t\t/* End PBXFileReference section */'
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Add build file
|
|
237
|
+
const buildFileEntry = `\t\t${buildFileId} /* ssl_config.json in Resources */ = {isa = PBXBuildFile; fileRef = ${fileRefId} /* ssl_config.json */; };`;
|
|
238
|
+
projectContent = projectContent.replace(
|
|
239
|
+
'/* End PBXBuildFile section */',
|
|
240
|
+
buildFileEntry + '\n\t\t/* End PBXBuildFile section */'
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
// Add to resources build phase
|
|
244
|
+
const resourcesPhaseMatch = projectContent.match(
|
|
245
|
+
/(\w+) \/\* Resources \*\/ = \{[^}]*files = \(([^)]*)\)/
|
|
246
|
+
);
|
|
247
|
+
if (resourcesPhaseMatch) {
|
|
248
|
+
const filesSection = resourcesPhaseMatch[2];
|
|
249
|
+
const newFilesSection =
|
|
250
|
+
filesSection +
|
|
251
|
+
`\t\t\t\t${buildFileId} /* ssl_config.json in Resources */,\n`;
|
|
252
|
+
projectContent = projectContent.replace(
|
|
253
|
+
`files = (${filesSection})`,
|
|
254
|
+
`files = (\n${newFilesSection}\t\t\t)`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Add to main group
|
|
259
|
+
const mainGroupMatch = projectContent.match(
|
|
260
|
+
new RegExp(
|
|
261
|
+
`(\\w+) /\\* ${projectName} \\*/ = \\{[^}]*children = \\(([^)]*)\\)`
|
|
262
|
+
)
|
|
263
|
+
);
|
|
264
|
+
if (mainGroupMatch) {
|
|
265
|
+
const childrenSection = mainGroupMatch[2];
|
|
266
|
+
const newChildrenSection =
|
|
267
|
+
childrenSection + `\t\t\t\t${fileRefId} /* ssl_config.json */,\n`;
|
|
268
|
+
projectContent = projectContent.replace(
|
|
269
|
+
`children = (${childrenSection})`,
|
|
270
|
+
`children = (\n${newChildrenSection}\t\t\t)`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Write back to file
|
|
275
|
+
fs.writeFileSync(projectPath, projectContent);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.warn(
|
|
278
|
+
'⚠️ Failed to add SSL config to Xcode project:',
|
|
279
|
+
error.message
|
|
280
|
+
);
|
|
281
|
+
console.warn(
|
|
282
|
+
'💡 File copied to ios/ directory, manual Xcode setup may be needed'
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return config;
|
|
287
|
+
},
|
|
288
|
+
]);
|
|
289
|
+
|
|
290
|
+
return config;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = withSslManager;
|