@tamer4lynx/cli 0.0.1
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/LICENSE +21 -0
- package/README.md +307 -0
- package/dist/android/autolink.js +272 -0
- package/dist/android/build.js +36 -0
- package/dist/android/bundle.js +99 -0
- package/dist/android/coreElements.js +129 -0
- package/dist/android/create.js +423 -0
- package/dist/android/getGradle.js +92 -0
- package/dist/android/postinstall-and.js +7 -0
- package/dist/android/postinstall.js +7 -0
- package/dist/android/syncDevClient.js +70 -0
- package/dist/common/buildDevApp.js +43 -0
- package/dist/common/codegen.js +69 -0
- package/dist/common/config.js +113 -0
- package/dist/common/create.js +170 -0
- package/dist/common/devServer.js +231 -0
- package/dist/common/hostConfig.js +256 -0
- package/dist/common/init.js +65 -0
- package/dist/common/postinstall.js +39 -0
- package/dist/common/start.js +5 -0
- package/dist/explorer/devLauncher.js +47 -0
- package/dist/explorer/patches.js +400 -0
- package/dist/explorer/ref.js +9 -0
- package/dist/index.js +6381 -0
- package/dist/ios/autolink.js +246 -0
- package/dist/ios/build.js +31 -0
- package/dist/ios/bundle.js +73 -0
- package/dist/ios/create.js +597 -0
- package/dist/ios/getPod.js +53 -0
- package/dist/ios/postinstall.js +7 -0
- package/package.json +92 -0
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { setupCocoaPods } from "./getPod";
|
|
5
|
+
import { randomBytes } from "crypto";
|
|
6
|
+
import { loadHostConfig, resolveIconPaths } from "../common/hostConfig";
|
|
7
|
+
const create = () => {
|
|
8
|
+
const generateId = () => randomBytes(12).toString('hex').toUpperCase();
|
|
9
|
+
let appName;
|
|
10
|
+
let bundleId;
|
|
11
|
+
let config;
|
|
12
|
+
try {
|
|
13
|
+
config = loadHostConfig();
|
|
14
|
+
appName = config.ios?.appName;
|
|
15
|
+
bundleId = config.ios?.bundleId;
|
|
16
|
+
if (!appName && !bundleId) {
|
|
17
|
+
throw new Error('"ios.appName" and "ios.bundleId" must be defined in tamer.config.json');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(`โ Error loading configuration: ${error.message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const iosDir = config.paths?.iosDir ?? "ios";
|
|
25
|
+
const rootDir = path.join(process.cwd(), iosDir);
|
|
26
|
+
const projectDir = path.join(rootDir, appName);
|
|
27
|
+
const xcodeprojDir = path.join(rootDir, `${appName}.xcodeproj`);
|
|
28
|
+
const bridgingHeader = `${appName}-Bridging-Header.h`;
|
|
29
|
+
function writeFile(filePath, content) {
|
|
30
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
31
|
+
fs.writeFileSync(filePath, content.trimStart(), "utf8");
|
|
32
|
+
}
|
|
33
|
+
// Clean up previous generation if it exists
|
|
34
|
+
if (fs.existsSync(rootDir)) {
|
|
35
|
+
console.log(`๐งน Removing existing directory: ${rootDir}`);
|
|
36
|
+
fs.rmSync(rootDir, { recursive: true, force: true });
|
|
37
|
+
}
|
|
38
|
+
console.log(`๐ Creating a new Tamer4Lynx project in: ${rootDir}`);
|
|
39
|
+
// --- Generate Xcode Object IDs ---
|
|
40
|
+
const ids = {
|
|
41
|
+
project: generateId(),
|
|
42
|
+
mainGroup: generateId(),
|
|
43
|
+
appGroup: generateId(),
|
|
44
|
+
productsGroup: generateId(),
|
|
45
|
+
frameworksGroup: generateId(),
|
|
46
|
+
appFile: generateId(),
|
|
47
|
+
appDelegateRef: generateId(),
|
|
48
|
+
sceneDelegateRef: generateId(),
|
|
49
|
+
viewControllerRef: generateId(),
|
|
50
|
+
mainStoryboardRef: generateId(),
|
|
51
|
+
assetsRef: generateId(),
|
|
52
|
+
launchStoryboardRef: generateId(),
|
|
53
|
+
lynxProviderRef: generateId(),
|
|
54
|
+
lynxInitRef: generateId(),
|
|
55
|
+
bridgingHeaderRef: generateId(),
|
|
56
|
+
mainStoryboardBaseRef: generateId(),
|
|
57
|
+
launchStoryboardBaseRef: generateId(),
|
|
58
|
+
nativeTarget: generateId(),
|
|
59
|
+
appDelegateBuildFile: generateId(),
|
|
60
|
+
sceneDelegateBuildFile: generateId(),
|
|
61
|
+
viewControllerBuildFile: generateId(),
|
|
62
|
+
lynxProviderBuildFile: generateId(),
|
|
63
|
+
lynxInitBuildFile: generateId(),
|
|
64
|
+
mainStoryboardBuildFile: generateId(),
|
|
65
|
+
assetsBuildFile: generateId(),
|
|
66
|
+
launchStoryboardBuildFile: generateId(),
|
|
67
|
+
frameworksBuildPhase: generateId(),
|
|
68
|
+
resourcesBuildPhase: generateId(),
|
|
69
|
+
sourcesBuildPhase: generateId(),
|
|
70
|
+
projectBuildConfigList: generateId(),
|
|
71
|
+
targetBuildConfigList: generateId(),
|
|
72
|
+
projectDebugConfig: generateId(),
|
|
73
|
+
projectReleaseConfig: generateId(),
|
|
74
|
+
targetDebugConfig: generateId(),
|
|
75
|
+
targetReleaseConfig: generateId(),
|
|
76
|
+
};
|
|
77
|
+
// --- Start File Generation ---
|
|
78
|
+
// Podfile
|
|
79
|
+
writeFile(path.join(rootDir, "Podfile"), `
|
|
80
|
+
source 'https://cdn.cocoapods.org/'
|
|
81
|
+
|
|
82
|
+
platform :ios, '13.0'
|
|
83
|
+
|
|
84
|
+
target '${appName}' do
|
|
85
|
+
pod 'Lynx', '3.3.0', :subspecs => [
|
|
86
|
+
'Framework',
|
|
87
|
+
], :modular_headers => true
|
|
88
|
+
|
|
89
|
+
pod 'PrimJS', '2.13.2', :subspecs => ['quickjs', 'napi']
|
|
90
|
+
|
|
91
|
+
# integrate image-service, log-service, and http-service
|
|
92
|
+
pod 'LynxService', '3.3.0', :subspecs => [
|
|
93
|
+
'Image',
|
|
94
|
+
'Log',
|
|
95
|
+
'Http',
|
|
96
|
+
]
|
|
97
|
+
pod 'SDWebImage','5.15.5'
|
|
98
|
+
pod 'SDWebImageWebPCoder', '0.11.0'
|
|
99
|
+
|
|
100
|
+
# GENERATED AUTOLINK DEPENDENCIES START
|
|
101
|
+
# This section is automatically generated by Tamer4Lynx.
|
|
102
|
+
# Manual edits will be overwritten.
|
|
103
|
+
# GENERATED AUTOLINK DEPENDENCIES END
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
post_install do |installer|
|
|
107
|
+
installer.pods_project.targets.each do |target|
|
|
108
|
+
if target.name == 'Lynx'
|
|
109
|
+
target.build_configurations.each do |config|
|
|
110
|
+
flags = [
|
|
111
|
+
'-Wno-vla-extension',
|
|
112
|
+
'-Wno-vla',
|
|
113
|
+
'-Wno-error=vla-extension',
|
|
114
|
+
'-Wno-deprecated-declarations',
|
|
115
|
+
'-Wno-deprecated',
|
|
116
|
+
'-Wno-macro-redefined',
|
|
117
|
+
'-Wno-enum-compare',
|
|
118
|
+
'-Wno-enum-compare-conditional',
|
|
119
|
+
'-Wno-enum-conversion'
|
|
120
|
+
].join(' ')
|
|
121
|
+
|
|
122
|
+
config.build_settings['OTHER_CPLUSPLUSFLAGS'] = "$(inherited) #{flags}"
|
|
123
|
+
config.build_settings['OTHER_CFLAGS'] = "$(inherited) #{flags}"
|
|
124
|
+
config.build_settings['CLANG_WARN_VLA'] = 'NO'
|
|
125
|
+
config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'NO'
|
|
126
|
+
config.build_settings['CLANG_WARN_ENUM_CONVERSION'] = 'NO'
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
`);
|
|
132
|
+
// --- App Files (same as before) ---
|
|
133
|
+
writeFile(path.join(projectDir, "AppDelegate.swift"), `
|
|
134
|
+
import UIKit
|
|
135
|
+
|
|
136
|
+
@UIApplicationMain
|
|
137
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
138
|
+
var window: UIWindow?
|
|
139
|
+
|
|
140
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
141
|
+
LynxInitProcessor.shared.setupEnvironment()
|
|
142
|
+
return true
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
`);
|
|
146
|
+
writeFile(path.join(projectDir, "ViewController.swift"), `
|
|
147
|
+
import UIKit
|
|
148
|
+
|
|
149
|
+
class ViewController: UIViewController {
|
|
150
|
+
|
|
151
|
+
override func viewDidLoad() {
|
|
152
|
+
super.viewDidLoad()
|
|
153
|
+
|
|
154
|
+
let lynxView = LynxView { builder in
|
|
155
|
+
builder.config = LynxConfig(provider: LynxProvider())
|
|
156
|
+
builder.screenSize = self.view.frame.size
|
|
157
|
+
builder.fontScale = 1.0
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
lynxView.preferredLayoutWidth = self.view.frame.size.width
|
|
161
|
+
lynxView.preferredLayoutHeight = self.view.frame.size.height
|
|
162
|
+
lynxView.layoutWidthMode = .exact
|
|
163
|
+
lynxView.layoutHeightMode = .exact
|
|
164
|
+
self.view.addSubview(lynxView)
|
|
165
|
+
|
|
166
|
+
lynxView.loadTemplate(fromURL: "main.lynx", initData: nil)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
`);
|
|
170
|
+
writeFile(path.join(projectDir, "LynxProvider.swift"), `
|
|
171
|
+
import Foundation
|
|
172
|
+
|
|
173
|
+
class LynxProvider: NSObject, LynxTemplateProvider {
|
|
174
|
+
func loadTemplate(withUrl url: String!, onComplete callback: LynxTemplateLoadBlock!) {
|
|
175
|
+
if let filePath = Bundle.main.path(forResource: url, ofType: "bundle") {
|
|
176
|
+
do {
|
|
177
|
+
let data = try Data(contentsOf: URL(fileURLWithPath: filePath))
|
|
178
|
+
callback(data, nil)
|
|
179
|
+
} catch {
|
|
180
|
+
print("Error reading file: \\(error.localizedDescription)")
|
|
181
|
+
callback(nil, error)
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
let urlError = NSError(domain: "com.lynx", code: 400, userInfo: [NSLocalizedDescriptionKey: "Invalid URL."])
|
|
185
|
+
callback(nil, urlError)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`);
|
|
190
|
+
// LynxInitProcessor.swift - provides a hook for autolinked native module registrations
|
|
191
|
+
writeFile(path.join(projectDir, "LynxInitProcessor.swift"), `
|
|
192
|
+
// Copyright 2024 The Lynx Authors. All rights reserved.
|
|
193
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
194
|
+
// LICENSE file in the root directory of this source tree.
|
|
195
|
+
|
|
196
|
+
import Foundation
|
|
197
|
+
|
|
198
|
+
// GENERATED IMPORTS START
|
|
199
|
+
// This section is automatically generated by Tamer4Lynx.
|
|
200
|
+
// Manual edits will be overwritten.
|
|
201
|
+
// GENERATED IMPORTS END
|
|
202
|
+
|
|
203
|
+
final class LynxInitProcessor {
|
|
204
|
+
static let shared = LynxInitProcessor()
|
|
205
|
+
private init() {}
|
|
206
|
+
|
|
207
|
+
func setupEnvironment() {
|
|
208
|
+
setupLynxEnv()
|
|
209
|
+
setupLynxService()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private func setupLynxEnv() {
|
|
213
|
+
// Ensure LynxEnv singleton is initialized
|
|
214
|
+
let env = LynxEnv.sharedInstance()
|
|
215
|
+
|
|
216
|
+
// init global config
|
|
217
|
+
// Assumes \`initWithProvider:\` is exposed to Swift as \`init(provider:)\`
|
|
218
|
+
let globalConfig = LynxConfig(provider: env.config.templateProvider)
|
|
219
|
+
|
|
220
|
+
// register global JS module
|
|
221
|
+
// GENERATED AUTOLINK START
|
|
222
|
+
|
|
223
|
+
// GENERATED AUTOLINK END
|
|
224
|
+
|
|
225
|
+
// prepare global config
|
|
226
|
+
env.prepareConfig(globalConfig)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private func setupLynxService() {
|
|
230
|
+
// prepare lynx service
|
|
231
|
+
// Assumes SDWebImage/SDWebImageWebPCoder exposes \`shared\` singletons to Swift
|
|
232
|
+
let webPCoder = SDImageWebPCoder.shared
|
|
233
|
+
SDImageCodersManager.shared.addCoder(webPCoder)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
`);
|
|
237
|
+
writeFile(path.join(projectDir, bridgingHeader), `
|
|
238
|
+
#import <Lynx/LynxConfig.h>
|
|
239
|
+
#import <Lynx/LynxEnv.h>
|
|
240
|
+
#import <Lynx/LynxTemplateProvider.h>
|
|
241
|
+
#import <Lynx/LynxView.h>
|
|
242
|
+
#import <Lynx/LynxModule.h>
|
|
243
|
+
#import <SDWebImage/SDWebImage.h>
|
|
244
|
+
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
|
|
245
|
+
`);
|
|
246
|
+
const appIconDir = path.join(projectDir, "Assets.xcassets", "AppIcon.appiconset");
|
|
247
|
+
fs.mkdirSync(appIconDir, { recursive: true });
|
|
248
|
+
const iconPaths = resolveIconPaths(process.cwd(), config);
|
|
249
|
+
if (iconPaths?.ios) {
|
|
250
|
+
const entries = fs.readdirSync(iconPaths.ios, { withFileTypes: true });
|
|
251
|
+
for (const e of entries) {
|
|
252
|
+
const dest = path.join(appIconDir, e.name);
|
|
253
|
+
if (e.isDirectory()) {
|
|
254
|
+
fs.cpSync(path.join(iconPaths.ios, e.name), dest, { recursive: true });
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
fs.copyFileSync(path.join(iconPaths.ios, e.name), dest);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
console.log("โ
Copied iOS icon from tamer.config.json icon.ios");
|
|
261
|
+
}
|
|
262
|
+
else if (iconPaths?.source) {
|
|
263
|
+
const ext = path.extname(iconPaths.source) || ".png";
|
|
264
|
+
const icon1024 = `Icon-1024${ext}`;
|
|
265
|
+
fs.copyFileSync(iconPaths.source, path.join(appIconDir, icon1024));
|
|
266
|
+
writeFile(path.join(appIconDir, "Contents.json"), JSON.stringify({
|
|
267
|
+
images: [{ filename: icon1024, idiom: "universal", platform: "ios", size: "1024x1024" }],
|
|
268
|
+
info: { author: "xcode", version: 1 }
|
|
269
|
+
}, null, 2));
|
|
270
|
+
console.log("โ
Copied app icon from tamer.config.json icon.source");
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
writeFile(path.join(appIconDir, "Contents.json"), `
|
|
274
|
+
{
|
|
275
|
+
"images" : [ { "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" } ],
|
|
276
|
+
"info" : { "author" : "xcode", "version" : 1 }
|
|
277
|
+
}
|
|
278
|
+
`);
|
|
279
|
+
}
|
|
280
|
+
// --- Xcode Project File (VALID TEMPLATE) ---
|
|
281
|
+
fs.mkdirSync(xcodeprojDir, { recursive: true });
|
|
282
|
+
writeFile(path.join(xcodeprojDir, "project.pbxproj"), `
|
|
283
|
+
// !$*UTF8*$!
|
|
284
|
+
{
|
|
285
|
+
archiveVersion = 1;
|
|
286
|
+
classes = {};
|
|
287
|
+
objectVersion = 56;
|
|
288
|
+
objects = {
|
|
289
|
+
/* Begin PBXBuildFile section */
|
|
290
|
+
${ids.appDelegateBuildFile} /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.appDelegateRef} /* AppDelegate.swift */; };
|
|
291
|
+
${ids.viewControllerBuildFile} /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.viewControllerRef} /* ViewController.swift */; };
|
|
292
|
+
${ids.mainStoryboardBuildFile} /* Base in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.mainStoryboardBaseRef} /* Base */; };
|
|
293
|
+
${ids.assetsBuildFile} /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ${ids.assetsRef} /* Assets.xcassets */; };
|
|
294
|
+
${ids.lynxProviderBuildFile} /* LynxProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.lynxProviderRef} /* LynxProvider.swift */; };
|
|
295
|
+
${ids.lynxInitBuildFile} /* LynxInitProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = ${ids.lynxInitRef} /* LynxInitProcessor.swift */; };
|
|
296
|
+
/* End PBXBuildFile section */
|
|
297
|
+
|
|
298
|
+
/* Begin PBXFileReference section */
|
|
299
|
+
${ids.appFile} /* ${appName}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${appName}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
300
|
+
${ids.appDelegateRef} /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate.swift"; sourceTree = "<group>"; };
|
|
301
|
+
${ids.viewControllerRef} /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ViewController.swift"; sourceTree = "<group>"; };
|
|
302
|
+
${ids.mainStoryboardBaseRef} /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Main.storyboard"; sourceTree = "<group>"; };
|
|
303
|
+
${ids.assetsRef} /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Assets.xcassets"; sourceTree = "<group>"; };
|
|
304
|
+
${ids.lynxProviderRef} /* LynxProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LynxProvider.swift"; sourceTree = "<group>"; };
|
|
305
|
+
${ids.lynxInitRef} /* LynxInitProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LynxInitProcessor.swift"; sourceTree = "<group>"; };
|
|
306
|
+
${ids.bridgingHeaderRef} /* ${bridgingHeader} */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "${bridgingHeader}"; sourceTree = "<group>"; };
|
|
307
|
+
/* End PBXFileReference section */
|
|
308
|
+
|
|
309
|
+
/* Begin PBXFrameworksBuildPhase section */
|
|
310
|
+
${ids.frameworksBuildPhase} /* Frameworks */ = {
|
|
311
|
+
isa = PBXFrameworksBuildPhase;
|
|
312
|
+
buildActionMask = 2147483647;
|
|
313
|
+
files = (
|
|
314
|
+
);
|
|
315
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
316
|
+
};
|
|
317
|
+
/* End PBXFrameworksBuildPhase section */
|
|
318
|
+
|
|
319
|
+
/* Begin PBXGroup section */
|
|
320
|
+
${ids.mainGroup} = {
|
|
321
|
+
isa = PBXGroup;
|
|
322
|
+
children = (
|
|
323
|
+
${ids.appGroup} /* ${appName} */,
|
|
324
|
+
${ids.productsGroup} /* Products */,
|
|
325
|
+
${ids.frameworksGroup} /* Frameworks */,
|
|
326
|
+
);
|
|
327
|
+
sourceTree = "<group>";
|
|
328
|
+
};
|
|
329
|
+
${ids.productsGroup} /* Products */ = {
|
|
330
|
+
isa = PBXGroup;
|
|
331
|
+
children = (
|
|
332
|
+
${ids.appFile} /* ${appName}.app */,
|
|
333
|
+
);
|
|
334
|
+
name = Products;
|
|
335
|
+
sourceTree = "<group>";
|
|
336
|
+
};
|
|
337
|
+
${ids.frameworksGroup} /* Frameworks */ = {
|
|
338
|
+
isa = PBXGroup;
|
|
339
|
+
children = (
|
|
340
|
+
);
|
|
341
|
+
name = Frameworks;
|
|
342
|
+
sourceTree = "<group>";
|
|
343
|
+
};
|
|
344
|
+
${ids.appGroup} /* ${appName} */ = {
|
|
345
|
+
isa = PBXGroup;
|
|
346
|
+
children = (
|
|
347
|
+
${ids.appDelegateRef} /* AppDelegate.swift */,
|
|
348
|
+
${ids.viewControllerRef} /* ViewController.swift */,
|
|
349
|
+
${ids.mainStoryboardRef} /* Main.storyboard */,
|
|
350
|
+
${ids.assetsRef} /* Assets.xcassets */,
|
|
351
|
+
${ids.lynxProviderRef} /* LynxProvider.swift */,
|
|
352
|
+
${ids.lynxInitRef} /* LynxInitProcessor.swift */,
|
|
353
|
+
${ids.bridgingHeaderRef} /* ${bridgingHeader} */,
|
|
354
|
+
);
|
|
355
|
+
path = "${appName}";
|
|
356
|
+
sourceTree = "<group>";
|
|
357
|
+
};
|
|
358
|
+
/* End PBXGroup section */
|
|
359
|
+
|
|
360
|
+
/* Begin PBXNativeTarget section */
|
|
361
|
+
${ids.nativeTarget} /* ${appName} */ = {
|
|
362
|
+
isa = PBXNativeTarget;
|
|
363
|
+
buildConfigurationList = ${ids.targetBuildConfigList} /* Build configuration list for PBXNativeTarget "${appName}" */;
|
|
364
|
+
buildPhases = (
|
|
365
|
+
${ids.sourcesBuildPhase} /* Sources */,
|
|
366
|
+
${ids.frameworksBuildPhase} /* Frameworks */,
|
|
367
|
+
${ids.resourcesBuildPhase} /* Resources */,
|
|
368
|
+
);
|
|
369
|
+
buildRules = (
|
|
370
|
+
);
|
|
371
|
+
dependencies = (
|
|
372
|
+
);
|
|
373
|
+
name = "${appName}";
|
|
374
|
+
productName = "${appName}";
|
|
375
|
+
productReference = ${ids.appFile} /* ${appName}.app */;
|
|
376
|
+
productType = "com.apple.product-type.application";
|
|
377
|
+
};
|
|
378
|
+
/* End PBXNativeTarget section */
|
|
379
|
+
|
|
380
|
+
/* Begin PBXProject section */
|
|
381
|
+
${ids.project} /* Project object */ = {
|
|
382
|
+
isa = PBXProject;
|
|
383
|
+
attributes = {
|
|
384
|
+
LastUpgradeCheck = 1530;
|
|
385
|
+
};
|
|
386
|
+
buildConfigurationList = ${ids.projectBuildConfigList} /* Build configuration list for PBXProject "${appName}" */;
|
|
387
|
+
compatibilityVersion = "Xcode 14.0";
|
|
388
|
+
developmentRegion = en;
|
|
389
|
+
hasScannedForEncodings = 0;
|
|
390
|
+
knownRegions = (
|
|
391
|
+
en,
|
|
392
|
+
Base,
|
|
393
|
+
);
|
|
394
|
+
mainGroup = ${ids.mainGroup};
|
|
395
|
+
productRefGroup = ${ids.productsGroup} /* Products */;
|
|
396
|
+
projectDirPath = "";
|
|
397
|
+
projectRoot = "";
|
|
398
|
+
targets = (
|
|
399
|
+
${ids.nativeTarget} /* ${appName} */,
|
|
400
|
+
);
|
|
401
|
+
};
|
|
402
|
+
/* End PBXProject section */
|
|
403
|
+
|
|
404
|
+
/* Begin PBXResourcesBuildPhase section */
|
|
405
|
+
${ids.resourcesBuildPhase} /* Resources */ = {
|
|
406
|
+
isa = PBXResourcesBuildPhase;
|
|
407
|
+
buildActionMask = 2147483647;
|
|
408
|
+
files = (
|
|
409
|
+
${ids.assetsBuildFile} /* Assets.xcassets in Resources */,
|
|
410
|
+
${ids.mainStoryboardBuildFile} /* Base in Resources */,
|
|
411
|
+
);
|
|
412
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
413
|
+
};
|
|
414
|
+
/* End PBXResourcesBuildPhase section */
|
|
415
|
+
|
|
416
|
+
/* Begin PBXSourcesBuildPhase section */
|
|
417
|
+
${ids.sourcesBuildPhase} /* Sources */ = {
|
|
418
|
+
isa = PBXSourcesBuildPhase;
|
|
419
|
+
buildActionMask = 2147483647;
|
|
420
|
+
files = (
|
|
421
|
+
${ids.lynxProviderBuildFile} /* LynxProvider.swift in Sources */,
|
|
422
|
+
${ids.lynxInitBuildFile} /* LynxInitProcessor.swift in Sources */,
|
|
423
|
+
${ids.viewControllerBuildFile} /* ViewController.swift in Sources */,
|
|
424
|
+
${ids.appDelegateBuildFile} /* AppDelegate.swift in Sources */,
|
|
425
|
+
);
|
|
426
|
+
runOnlyForDeploymentPostprocessing = 0;
|
|
427
|
+
};
|
|
428
|
+
/* End PBXSourcesBuildPhase section */
|
|
429
|
+
|
|
430
|
+
/* Begin PBXVariantGroup section */
|
|
431
|
+
${ids.mainStoryboardRef} /* Main.storyboard */ = {
|
|
432
|
+
isa = PBXVariantGroup;
|
|
433
|
+
children = (
|
|
434
|
+
${ids.mainStoryboardBaseRef} /* Base */,
|
|
435
|
+
);
|
|
436
|
+
name = "Main.storyboard";
|
|
437
|
+
sourceTree = "<group>";
|
|
438
|
+
};
|
|
439
|
+
/* End PBXVariantGroup section */
|
|
440
|
+
|
|
441
|
+
/* Begin XCBuildConfiguration section */
|
|
442
|
+
${ids.projectDebugConfig} /* Debug */ = {
|
|
443
|
+
isa = XCBuildConfiguration;
|
|
444
|
+
buildSettings = {
|
|
445
|
+
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
446
|
+
CLANG_ANALYZER_NONNULL = YES;
|
|
447
|
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
448
|
+
CLANG_CXX_LIBRARY = "libc++";
|
|
449
|
+
CLANG_ENABLE_MODULES = YES;
|
|
450
|
+
CLANG_ENABLE_OBJC_ARC = YES;
|
|
451
|
+
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
452
|
+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
453
|
+
CLANG_WARN_EMPTY_BODY = YES;
|
|
454
|
+
CLANG_WARN_INT_CONVERSION = YES;
|
|
455
|
+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
456
|
+
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
457
|
+
COPY_PHASE_STRIP = NO;
|
|
458
|
+
DEBUG_INFORMATION_FORMAT = dwarf;
|
|
459
|
+
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
460
|
+
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
461
|
+
GCC_NO_COMMON_BLOCKS = YES;
|
|
462
|
+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
463
|
+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
464
|
+
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
465
|
+
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
466
|
+
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
|
467
|
+
SDKROOT = iphoneos;
|
|
468
|
+
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
|
469
|
+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
|
470
|
+
};
|
|
471
|
+
name = Debug;
|
|
472
|
+
};
|
|
473
|
+
${ids.projectReleaseConfig} /* Release */ = {
|
|
474
|
+
isa = XCBuildConfiguration;
|
|
475
|
+
buildSettings = {
|
|
476
|
+
ALWAYS_SEARCH_USER_PATHS = NO;
|
|
477
|
+
CLANG_ANALYZER_NONNULL = YES;
|
|
478
|
+
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
|
479
|
+
CLANG_CXX_LIBRARY = "libc++";
|
|
480
|
+
CLANG_ENABLE_MODULES = YES;
|
|
481
|
+
CLANG_ENABLE_OBJC_ARC = YES;
|
|
482
|
+
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
|
483
|
+
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
|
484
|
+
CLANG_WARN_EMPTY_BODY = YES;
|
|
485
|
+
CLANG_WARN_INT_CONVERSION = YES;
|
|
486
|
+
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
|
487
|
+
CLANG_WARN_UNREACHABLE_CODE = YES;
|
|
488
|
+
COPY_PHASE_STRIP = NO;
|
|
489
|
+
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
|
490
|
+
ENABLE_NS_ASSERTIONS = NO;
|
|
491
|
+
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
|
492
|
+
GCC_C_LANGUAGE_STANDARD = gnu11;
|
|
493
|
+
GCC_NO_COMMON_BLOCKS = YES;
|
|
494
|
+
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
|
495
|
+
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
|
496
|
+
GCC_WARN_UNUSED_VARIABLE = YES;
|
|
497
|
+
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
|
498
|
+
MTL_ENABLE_DEBUG_INFO = NO;
|
|
499
|
+
SDKROOT = iphoneos;
|
|
500
|
+
SWIFT_COMPILATION_MODE = wholemodule;
|
|
501
|
+
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
502
|
+
};
|
|
503
|
+
name = Release;
|
|
504
|
+
};
|
|
505
|
+
${ids.targetDebugConfig} /* Debug */ = {
|
|
506
|
+
isa = XCBuildConfiguration;
|
|
507
|
+
buildSettings = {
|
|
508
|
+
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
509
|
+
CURRENT_PROJECT_VERSION = 1;
|
|
510
|
+
GENERATE_INFOPLIST_FILE = YES;
|
|
511
|
+
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
|
512
|
+
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
513
|
+
MARKETING_VERSION = "1.0";
|
|
514
|
+
PRODUCT_BUNDLE_IDENTIFIER = "${bundleId}";
|
|
515
|
+
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
516
|
+
SWIFT_OBJC_BRIDGING_HEADER = "${appName}/${bridgingHeader}";
|
|
517
|
+
SWIFT_VERSION = 5.0;
|
|
518
|
+
TARGETED_DEVICE_FAMILY = "1,2";
|
|
519
|
+
};
|
|
520
|
+
name = Debug;
|
|
521
|
+
};
|
|
522
|
+
${ids.targetReleaseConfig} /* Release */ = {
|
|
523
|
+
isa = XCBuildConfiguration;
|
|
524
|
+
buildSettings = {
|
|
525
|
+
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
|
526
|
+
CURRENT_PROJECT_VERSION = 1;
|
|
527
|
+
GENERATE_INFOPLIST_FILE = YES;
|
|
528
|
+
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
|
529
|
+
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
530
|
+
MARKETING_VERSION = "1.0";
|
|
531
|
+
PRODUCT_BUNDLE_IDENTIFIER = "${bundleId}";
|
|
532
|
+
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
533
|
+
SWIFT_OBJC_BRIDGING_HEADER = "${appName}/${bridgingHeader}";
|
|
534
|
+
SWIFT_VERSION = 5.0;
|
|
535
|
+
TARGETED_DEVICE_FAMILY = "1,2";
|
|
536
|
+
};
|
|
537
|
+
name = Release;
|
|
538
|
+
};
|
|
539
|
+
/* End XCBuildConfiguration section */
|
|
540
|
+
|
|
541
|
+
/* Begin XCConfigurationList section */
|
|
542
|
+
${ids.projectBuildConfigList} /* Build configuration list for PBXProject "${appName}" */ = {
|
|
543
|
+
isa = XCConfigurationList;
|
|
544
|
+
buildConfigurations = (
|
|
545
|
+
${ids.projectDebugConfig} /* Debug */,
|
|
546
|
+
${ids.projectReleaseConfig} /* Release */,
|
|
547
|
+
);
|
|
548
|
+
defaultConfigurationIsVisible = 0;
|
|
549
|
+
defaultConfigurationName = Release;
|
|
550
|
+
};
|
|
551
|
+
${ids.targetBuildConfigList} /* Build configuration list for PBXNativeTarget "${appName}" */ = {
|
|
552
|
+
isa = XCConfigurationList;
|
|
553
|
+
buildConfigurations = (
|
|
554
|
+
${ids.targetDebugConfig} /* Debug */,
|
|
555
|
+
${ids.targetReleaseConfig} /* Release */,
|
|
556
|
+
);
|
|
557
|
+
defaultConfigurationIsVisible = 0;
|
|
558
|
+
defaultConfigurationName = Release;
|
|
559
|
+
};
|
|
560
|
+
/* End XCConfigurationList section */
|
|
561
|
+
};
|
|
562
|
+
rootObject = ${ids.project} /* Project object */;
|
|
563
|
+
}
|
|
564
|
+
`);
|
|
565
|
+
// Minimal Main.storyboard
|
|
566
|
+
fs.mkdirSync(path.join(projectDir, "Base.lproj"), { recursive: true });
|
|
567
|
+
writeFile(path.join(projectDir, "Base.lproj", "Main.storyboard"), `
|
|
568
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
569
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
|
570
|
+
<dependencies>
|
|
571
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
|
572
|
+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
573
|
+
</dependencies>
|
|
574
|
+
<scenes>
|
|
575
|
+
<scene sceneID="tne-QT-ifu">
|
|
576
|
+
<objects>
|
|
577
|
+
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
|
|
578
|
+
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
|
579
|
+
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
580
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
581
|
+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
582
|
+
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
|
583
|
+
</view>
|
|
584
|
+
</viewController>
|
|
585
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
|
586
|
+
</objects>
|
|
587
|
+
</scene>
|
|
588
|
+
</scenes>
|
|
589
|
+
</document>
|
|
590
|
+
`);
|
|
591
|
+
console.log(`โ
iOS Swift project created at ${rootDir}`);
|
|
592
|
+
async function finalizeProjectSetup() {
|
|
593
|
+
await setupCocoaPods(rootDir);
|
|
594
|
+
}
|
|
595
|
+
finalizeProjectSetup();
|
|
596
|
+
};
|
|
597
|
+
export default create;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
/**
|
|
5
|
+
* Checks if CocoaPods is installed on the system.
|
|
6
|
+
* @returns {boolean} True if installed, false otherwise.
|
|
7
|
+
*/
|
|
8
|
+
function isCocoaPodsInstalled() {
|
|
9
|
+
try {
|
|
10
|
+
// The `command -v` command is a reliable way to check if a command exists in the shell's PATH.
|
|
11
|
+
// We pipe the output to /dev/null to keep the console clean.
|
|
12
|
+
execSync('command -v pod >/dev/null 2>&1');
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Sets up the CocoaPods environment for the project.
|
|
21
|
+
* @param rootDir The root directory of the iOS project.
|
|
22
|
+
*/
|
|
23
|
+
export async function setupCocoaPods(rootDir) {
|
|
24
|
+
// First, check if CocoaPods is available.
|
|
25
|
+
if (!isCocoaPodsInstalled()) {
|
|
26
|
+
console.error("โ CocoaPods is not installed.");
|
|
27
|
+
console.log(" CocoaPods is required to manage native dependencies for iOS development.");
|
|
28
|
+
console.log(" Please install it using one of the following commands:");
|
|
29
|
+
console.log("\n Using Homebrew (Recommended):");
|
|
30
|
+
console.log(" brew install cocoapods");
|
|
31
|
+
console.log("\n Using RubyGems:");
|
|
32
|
+
console.log(" sudo gem install cocoapods\n");
|
|
33
|
+
process.exit(1); // Exit the script with an error code.
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
console.log("๐ฆ CocoaPods is installed. Proceeding with dependency installation...");
|
|
37
|
+
const podfilePath = path.join(rootDir, 'Podfile');
|
|
38
|
+
if (!fs.existsSync(podfilePath)) {
|
|
39
|
+
throw new Error(`Podfile not found at ${podfilePath}`);
|
|
40
|
+
}
|
|
41
|
+
console.log(`๐ Executing pod install in: ${rootDir}`);
|
|
42
|
+
execSync(`pod install`, {
|
|
43
|
+
cwd: rootDir,
|
|
44
|
+
stdio: "inherit",
|
|
45
|
+
});
|
|
46
|
+
console.log("โ
CocoaPods dependencies installed successfully.");
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error("โ Failed to install CocoaPods dependencies.", err.message);
|
|
50
|
+
// Exit the process if pod installation fails, as it's a critical step.
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|