catalyst-core 0.0.3-canary.1 → 0.0.3-canary.10

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.
Files changed (84) hide show
  1. package/README.md +2 -3
  2. package/babel.config.js +32 -0
  3. package/bin/catalyst.js +28 -15
  4. package/changelog.md +56 -23
  5. package/dist/native/androidProject/app/build.gradle.kts +185 -31
  6. package/dist/native/androidProject/app/src/main/AndroidManifest.xml +22 -3
  7. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +535 -0
  8. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +188 -0
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +356 -0
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/Utils.kt +64 -0
  11. package/dist/native/androidProject/app/src/main/java/{com/example/myapplication → io/yourname/androidproject}/WebCacheManager.kt +91 -33
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +221 -0
  13. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/CameraUtils.kt +269 -0
  14. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/DeviceInfoUtils.kt +60 -0
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/DownloadUtils.kt +251 -0
  16. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FileSizeRouterUtils.kt +347 -0
  17. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FileUtils.kt +334 -0
  18. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +362 -0
  19. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/IntentUtils.kt +274 -0
  20. package/dist/native/androidProject/app/src/main/res/drawable/splashscreen_fallback.png +0 -0
  21. package/dist/native/androidProject/app/src/main/res/layout/activity_main.xml +12 -6
  22. package/dist/native/androidProject/app/src/main/res/values/strings.xml +1 -1
  23. package/dist/native/androidProject/app/src/main/res/xml/file_paths.xml +18 -0
  24. package/dist/native/androidProject/gradle/libs.versions.toml +1 -1
  25. package/dist/native/androidProject/gradle/wrapper/gradle-wrapper.properties +1 -1
  26. package/dist/native/androidProject/keystore/Untitled +0 -0
  27. package/dist/native/androidProject/keystore/release-key.jks +0 -0
  28. package/dist/native/androidProject/settings.gradle.kts +1 -1
  29. package/dist/native/androidSetup.js +4 -3
  30. package/dist/native/bridge/WebBridge.js +46 -0
  31. package/dist/native/bridge/constants/NativeInterfaces.js +24 -0
  32. package/dist/native/bridge/errors.js +39 -0
  33. package/dist/native/bridge/hooks.js +77 -0
  34. package/dist/native/bridge/standardizedHooks.js +80 -0
  35. package/dist/native/bridge/useBaseHook.js +43 -0
  36. package/dist/native/bridge/utils/NativeBridge.js +60 -0
  37. package/dist/native/buildAppAndroid.js +81 -7
  38. package/dist/native/buildAppIos.js +18 -14
  39. package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/AccentColor.colorset/Contents.json +8 -8
  40. package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/AppIcon.appiconset/Contents.json +10 -10
  41. package/dist/native/iosnativeWebView/iosnativeWebView/Assets.xcassets/Contents.json +4 -4
  42. package/dist/native/iosnativeWebView/iosnativeWebView/ContentView.swift +15 -0
  43. package/dist/native/iosnativeWebView/iosnativeWebView/ImageHandler.swift +288 -0
  44. package/dist/native/iosnativeWebView/iosnativeWebView/Info.plist +2 -0
  45. package/dist/native/iosnativeWebView/iosnativeWebView/NativeBridge.swift +217 -0
  46. package/dist/native/iosnativeWebView/iosnativeWebView/Preview Content/Preview Assets.xcassets/Contents.json +4 -4
  47. package/dist/native/iosnativeWebView/iosnativeWebView/WebView.swift +17 -0
  48. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +8 -0
  49. package/dist/native/renameAndroidProject.js +79 -0
  50. package/dist/native/setupEmulatorIos.js +22 -5
  51. package/dist/native/setupServer.js +28 -0
  52. package/dist/native/terminalProgress.js +10 -10
  53. package/dist/native/utils.js +5 -6
  54. package/dist/otel.js +4 -0
  55. package/dist/scripts/build.js +2 -9
  56. package/dist/scripts/devBuild.js +2 -9
  57. package/dist/scripts/devServe.js +2 -4
  58. package/dist/scripts/loadEnvironmentVariables.js +2 -1
  59. package/dist/scripts/loadScriptsBeforeServerStarts.js +2 -2
  60. package/dist/scripts/registerAliases.js +1 -1
  61. package/dist/scripts/scriptUtils.js +2 -2
  62. package/dist/scripts/serve.js +2 -4
  63. package/dist/scripts/start.js +4 -4
  64. package/dist/sentry.js +2 -0
  65. package/dist/server/expressServer.js +1 -1
  66. package/dist/server/renderer/document/Body.js +3 -3
  67. package/dist/server/renderer/document/Head.js +2 -2
  68. package/dist/server/renderer/extract.js +4 -4
  69. package/dist/server/renderer/handler.js +13 -7
  70. package/dist/server/renderer/index.js +1 -1
  71. package/dist/server/startServer.js +4 -3
  72. package/dist/server/utils/userAgentUtil.js +1 -1
  73. package/dist/server/utils/validator.js +1 -1
  74. package/dist/webpack/babel.config.client.js +1 -1
  75. package/dist/webpack/babel.config.ssr.js +1 -1
  76. package/dist/webpack/base.babel.js +4 -4
  77. package/dist/webpack/development.client.babel.js +17 -2
  78. package/dist/webpack/production.client.babel.js +2 -2
  79. package/dist/webpack/production.ssr.babel.js +2 -2
  80. package/package.json +13 -4
  81. package/babel.config.json +0 -21
  82. package/dist/native/androidProject/app/src/androidTest/java/com/example/myapplication/ExampleInstrumentedTest.kt +0 -24
  83. package/dist/native/androidProject/app/src/main/java/com/example/myapplication/MainActivity.kt +0 -278
  84. package/dist/native/androidProject/app/src/test/java/com/example/myapplication/ExampleUnitTest.kt +0 -17
package/README.md CHANGED
@@ -9,14 +9,13 @@
9
9
 
10
10
  - Overview
11
11
  - Installation
12
-
12
+
13
13
  ## Overview
14
14
 
15
15
  Catalyst offers a comprehensive suite of features designed for modern web development. It includes isomorphic rendering for optimal performance, an extendable server with full-stack capabilities, and configurable state management. The framework employs smart prefetching of data and chunks, allows easy configuration of global styles and layouts, and provides SEO optimization at both global and page levels.
16
16
 
17
17
  This version adds support for Universal app for both Android and iOS. Please checkout [Universal App Documentaion](https://catalyst.1mg.com/public_docs/content/Universal%20App/RunUniversalApp)
18
18
 
19
-
20
19
  ## Installation
21
20
 
22
21
  **System Requirements**
@@ -38,7 +37,7 @@ You will see some prompts to configure your application.
38
37
  cd <name-of-your-project> && npm run start
39
38
  ```
40
39
 
41
- The development server will start at ```http://localhost:3005```
40
+ The development server will start at `http://localhost:3005`
42
41
 
43
42
  ## Documentation
44
43
 
@@ -0,0 +1,32 @@
1
+ module.exports = (api) => {
2
+ api.cache(true)
3
+
4
+ return {
5
+ presets: [
6
+ [
7
+ "@babel/preset-typescript",
8
+ {
9
+ isTSX: true,
10
+ allExtensions: true,
11
+ },
12
+ ],
13
+ [
14
+ "@babel/preset-env",
15
+ {
16
+ targets: {
17
+ node: "current",
18
+ },
19
+ },
20
+ ],
21
+ ["@babel/preset-react", { runtime: "automatic" }],
22
+ ],
23
+ compact: true,
24
+ plugins: ["@loadable/babel-plugin"],
25
+ env: {
26
+ test: {
27
+ presets: ["@babel/preset-react"],
28
+ },
29
+ },
30
+ ignore: ["__TEST__"],
31
+ }
32
+ }
package/bin/catalyst.js CHANGED
@@ -8,9 +8,17 @@ const args = process.argv.slice(2)
8
8
 
9
9
  // Array of valid commands
10
10
  const validCommands = [
11
- "build", "start", "serve", "devBuild", "devServe",
12
- "buildApp", "buildApp:ios", "buildApp:android",
13
- "setupEmulator", "setupEmulator:ios", "setupEmulator:android"
11
+ "build",
12
+ "start",
13
+ "serve",
14
+ "devBuild",
15
+ "devServe",
16
+ "buildApp",
17
+ "buildApp:ios",
18
+ "buildApp:android",
19
+ "setupEmulator",
20
+ "setupEmulator:ios",
21
+ "setupEmulator:android",
14
22
  ]
15
23
 
16
24
  // Map of platform-specific commands to their script paths
@@ -18,17 +26,16 @@ const platformScripts = {
18
26
  "setupEmulator:ios": "../dist/native/setupEmulatorIos.js",
19
27
  "setupEmulator:android": "../dist/native/androidSetup.js",
20
28
  "buildApp:ios": "../dist/native/buildAppIos.js",
21
- "buildApp:android": "../dist/native/buildAppAndroid.js"
29
+ "buildApp:android": "../dist/native/buildAppAndroid.js",
22
30
  }
23
31
 
24
32
  // Helper to check if arg is a platform command
25
33
  const isPlatformCommand = (arg, prefix) => {
26
34
  if (!arg.startsWith(`${prefix}:`)) return false
27
- const platform = arg.split(':')[1]
28
- return ['ios', 'android'].includes(platform) || platform === undefined
35
+ const platform = arg.split(":")[1]
36
+ return ["ios", "android"].includes(platform) || platform === undefined
29
37
  }
30
38
 
31
-
32
39
  // Helper function to run a platform command
33
40
  const runPlatformCommand = (baseCommand, platform) => {
34
41
  const command = `${baseCommand}:${platform}`
@@ -42,7 +49,7 @@ const runPlatformCommand = (baseCommand, platform) => {
42
49
 
43
50
  // Helper function to run commands for all platforms
44
51
  const runAllPlatforms = (baseCommand) => {
45
- const platforms = ['ios', 'android']
52
+ const platforms = ["ios", "android"]
46
53
  for (const platform of platforms) {
47
54
  const result = runPlatformCommand(baseCommand, platform)
48
55
  if (result.status !== 0) {
@@ -54,8 +61,14 @@ const runAllPlatforms = (baseCommand) => {
54
61
  }
55
62
 
56
63
  const scriptIndex = args.findIndex(
57
- (x) => x === "build" || x === "start" || x === "serve" || x === "devBuild" || x === "devServe" ||
58
- isPlatformCommand(x, 'buildApp') || isPlatformCommand(x, 'setupEmulator')
64
+ (x) =>
65
+ x === "build" ||
66
+ x === "start" ||
67
+ x === "serve" ||
68
+ x === "devBuild" ||
69
+ x === "devServe" ||
70
+ isPlatformCommand(x, "buildApp") ||
71
+ isPlatformCommand(x, "setupEmulator")
59
72
  )
60
73
  const script = scriptIndex === -1 ? args[0] : args[scriptIndex]
61
74
  const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : []
@@ -92,17 +105,17 @@ function handleProcessResult(result) {
92
105
  if (result.signal === "SIGKILL") {
93
106
  console.log(
94
107
  "The build failed because the process exited too early. " +
95
- "This probably means the system ran out of memory or someone called " +
96
- "`kill -9` on the process."
108
+ "This probably means the system ran out of memory or someone called " +
109
+ "`kill -9` on the process."
97
110
  )
98
111
  } else if (result.signal === "SIGTERM") {
99
112
  console.log(
100
113
  "The build failed because the process exited too early. " +
101
- "Someone might have called `kill` or `killall`, or the system could " +
102
- "be shutting down."
114
+ "Someone might have called `kill` or `killall`, or the system could " +
115
+ "be shutting down."
103
116
  )
104
117
  }
105
118
  process.exit(1)
106
119
  }
107
120
  process.exit(result.status)
108
- }
121
+ }
package/changelog.md CHANGED
@@ -1,36 +1,69 @@
1
1
  # Changelog
2
2
 
3
- ## [0.0.3-canary.1] - 31-01-2025
3
+ ## [0.0.3-canary.10] - 2025-09-11
4
4
 
5
- ### Changes
5
+ - **Sentry import bug fix**
6
+ - **Open telemetry SDK**
6
7
 
7
- # Native WebView Implementation and Cache Management Updates
8
+ ## [0.0.3-canary.9] - 2025-09-11
8
9
 
9
- ## Overview
10
- This PR introduces native WebView implementations for both Android and iOS platforms, along with significant cache management improvements and bug fixes.
10
+ - **App name configuration**
11
+ - **Device Info API**
12
+ - **Access control configuration**
11
13
 
12
- ## Changes
14
+ ## [0.0.3-canary.8] - 2025-01-06
13
15
 
14
- ### New Features
15
- - Implemented native Android WebView with cache management functionality
16
- - Added iOS native WebView implementation with custom cache handling
17
- - Introduced new cache pattern management system
16
+ - **App icon configuration**
17
+ - **Splash screen integration**
18
+ - **Url Whitelisting**
18
19
 
19
- ### Technical Implementation Details
20
- - Android:
21
- - Added complete Android project structure with WebView implementation
22
- - Implemented `WebCacheManager.kt` for handling cache operations
23
- - Set up Gradle configuration and project dependencies
20
+ ## [0.0.3-canary.7] - 2025-01-06
24
21
 
25
- - iOS:
26
- - Created iOS native WebView project with Swift
27
- - Implemented `CacheManager.swift` and `ResourceURLProtocol.swift` for cache handling
28
- - Added WebView navigation and view model components
22
+ ### 🚀 Features
29
23
 
24
+ - **Native API Integration**: Enhanced native module integration for better performance
25
+ - **Automated IP Resolution**: Intelligent network detection eliminates manual IP configuration
26
+ - **Universal Build System**: Streamlined one-command builds for both Android and iOS platforms
27
+ - **Enhanced CLI Interface**: Improved command-line tools for better developer experience
30
28
 
31
- ### Other Changes
32
- - Enhanced terminal progress reporting
33
- - Updated documentation and README
29
+ ### 🐛 Bug Fixes
30
+
31
+ - Fixed IP address detection issues on development environments
32
+ - Resolved build configuration conflicts between platforms
33
+ - Improved error handling and recovery mechanisms
34
+
35
+ ### 🔧 Improvements
36
+
37
+ - **Performance**: Optimized native module loading and execution
38
+ - **Developer Experience**: Enhanced CLI with better error messages and debugging info
39
+ - **Configuration**: Dynamic config updates without requiring restarts
40
+ - **Build Process**: Faster and more reliable build pipeline
41
+
42
+ ### 🧪 Testing & Validation
43
+
44
+ - ✅ **Android Build**: Verified APK generation, installation, and runtime behavior
45
+ - ✅ **iOS Build**: Tested build process and device compatibility
46
+ - ✅ **IP Detection**: Validated automatic network resolution across platforms
47
+ - ✅ **Native Modules**: Confirmed API integration and performance benchmarks
48
+ - ✅ **CLI Operations**: Tested enhanced command-line workflows and error handling
49
+
50
+ ### 🔄 Breaking Changes
51
+
52
+ **None** - All changes maintain backward compatibility while enhancing existing functionality
53
+
54
+ ### 📝 Technical Details
55
+
56
+ - Improved native API bridge for better cross-platform communication
57
+ - Enhanced error reporting with detailed stack traces and suggestions
58
+ - Optimized build configuration for faster development cycles
59
+ - Added comprehensive logging for debugging and monitoring
60
+
61
+ ### 🔗 Migration Notes
62
+
63
+ - No migration steps required
64
+ - Existing projects will automatically benefit from improvements
65
+ - Optional: Update CLI usage to leverage new enhanced features
34
66
 
35
67
  ## Version
36
- - Target version: 0.0.3-canary.1
68
+
69
+ - Target version: 0.0.3-canary.7
@@ -1,8 +1,19 @@
1
1
  import java.net.NetworkInterface
2
2
  import java.io.File
3
3
  import java.util.Properties
4
+ import org.json.JSONObject
5
+ import org.json.JSONArray
6
+
7
+ buildscript {
8
+ dependencies {
9
+ classpath("org.json:json:20231013")
10
+ }
11
+ }
4
12
 
5
13
  val configPath: String? by project.properties
14
+ val keystorePassword: String? by project.properties // Changed from keyStorePassword to keystorePassword
15
+ val keyAlias: String? by project.properties
16
+ val keyPassword: String? by project.properties
6
17
 
7
18
  fun getLocalIpAddress(): String {
8
19
  return NetworkInterface.getNetworkInterfaces().toList()
@@ -18,35 +29,73 @@ plugins {
18
29
  }
19
30
 
20
31
  android {
21
- namespace = "com.example.androidProject"
32
+ namespace = "io.yourname.androidproject"
22
33
  compileSdk = 34
23
34
 
24
35
  defaultConfig {
25
- applicationId = "com.example.androidProject"
36
+ applicationId = "io.yourname.androidproject"
26
37
  minSdk = 24
27
38
  targetSdk = 34
28
39
  versionCode = 1
29
- versionName = "1.0"
40
+ versionName = "1.1"
30
41
  testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
31
42
  buildConfigField("String", "LOCAL_IP", "\"${getLocalIpAddress()}\"")
32
43
  }
33
44
 
45
+ // Add signing configuration for app bundle
46
+ signingConfigs {
47
+ create("release") {
48
+ // Make sure the keystore file exists before referencing it
49
+ val keystoreFile = file("../keystore/release-key.jks")
50
+ if (keystoreFile.exists()) {
51
+ storeFile = file("../keystore/release-key.jks")
52
+ storePassword = "test@123"
53
+ keyAlias = "release"
54
+ keyPassword = "test@123"
55
+ } else {
56
+ // Log a warning if the keystore doesn't exist yet
57
+ logger.warn("Keystore file not found at ${keystoreFile.absolutePath}. Run the generateKeystore task first.")
58
+ }
59
+ }
60
+ }
61
+
34
62
  buildTypes {
35
63
  debug {
36
64
  manifestPlaceholders += mapOf("allowCleartextTraffic" to true)
65
+ applicationIdSuffix = ".debug"
66
+ versionNameSuffix = "-debug"
37
67
  isMinifyEnabled = false
38
68
  buildConfigField("Boolean", "ALLOW_MIXED_CONTENT", "true")
39
69
  buildConfigField("String", "LOCAL_IP", "\"${getLocalIpAddress()}\"")
40
70
  }
41
71
  release {
42
72
  manifestPlaceholders += mapOf("allowCleartextTraffic" to false)
43
- isMinifyEnabled = false
73
+ isMinifyEnabled = true
74
+ isShrinkResources = true
44
75
  proguardFiles(
45
76
  getDefaultProguardFile("proguard-android-optimize.txt"),
46
77
  "proguard-rules.pro"
47
78
  )
48
79
  buildConfigField("Boolean", "ALLOW_MIXED_CONTENT", "false")
49
80
  buildConfigField("String", "LOCAL_IP", "\"127.0.0.1\"")
81
+
82
+ // Only apply signing config if the keystore exists
83
+ if (file("../keystore/release-key.jks").exists()) {
84
+ signingConfig = signingConfigs.getByName("release")
85
+ }
86
+ }
87
+ }
88
+
89
+ // Configure App Bundle settings
90
+ bundle {
91
+ language {
92
+ enableSplit = true
93
+ }
94
+ density {
95
+ enableSplit = true
96
+ }
97
+ abi {
98
+ enableSplit = true
50
99
  }
51
100
  }
52
101
 
@@ -63,6 +112,23 @@ android {
63
112
  viewBinding = true
64
113
  buildConfig = true
65
114
  }
115
+
116
+ packaging {
117
+ resources {
118
+ excludes.add("**/route-manifest.json.gz")
119
+ excludes.add("**/route-manifest.json.br")
120
+ excludes.add("META-INF/LICENSE")
121
+ excludes.add("META-INF/NOTICE")
122
+ excludes.add("META-INF/INDEX.LIST")
123
+ excludes.add("META-INF/io.netty.versions.properties")
124
+ }
125
+ }
126
+
127
+ // Configure lint options
128
+ lint {
129
+ checkReleaseBuilds = true
130
+ abortOnError = true
131
+ }
66
132
  }
67
133
 
68
134
  dependencies {
@@ -75,6 +141,16 @@ dependencies {
75
141
  androidTestImplementation(libs.androidx.espresso.core)
76
142
  implementation("androidx.webkit:webkit:1.12.1")
77
143
  implementation("org.json:json:20231013")
144
+ implementation("androidx.core:core-splashscreen:1.0.1")
145
+
146
+ // Ktor Server dependencies for FrameworkServer (~200KB total)
147
+ implementation("io.ktor:ktor-server-core:2.3.7")
148
+ implementation("io.ktor:ktor-server-netty:2.3.7")
149
+ implementation("io.ktor:ktor-server-content-negotiation:2.3.7")
150
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
151
+
152
+ // SLF4J simple logger for Ktor (optional, can be excluded if needed)
153
+ implementation("org.slf4j:slf4j-simple:2.0.9")
78
154
  }
79
155
 
80
156
  // Task to verify local IP
@@ -129,52 +205,130 @@ tasks.register("generateWebViewConfig") {
129
205
  }
130
206
 
131
207
  val configContent = configJsonFile.readText()
208
+
209
+ val jsonObject = JSONObject(configContent)
210
+
211
+ if (!jsonObject.has("WEBVIEW_CONFIG")) {
212
+ throw GradleException("WEBVIEW_CONFIG not found in config file")
213
+ }
214
+
215
+ val webviewConfig = jsonObject.getJSONObject("WEBVIEW_CONFIG")
216
+
217
+ val properties = Properties()
132
218
 
133
- // Extract WEBVIEW_CONFIG section
134
- val webviewConfigRegex = """"WEBVIEW_CONFIG"\s*:\s*\{([^}]*)\}""".toRegex()
135
- val webviewConfigMatch = webviewConfigRegex.find(configContent)
136
- val webviewConfigContent = webviewConfigMatch?.groupValues?.get(1)
219
+ // Set different IP based on build type
220
+ if (gradle.startParameter.taskNames.any { it.contains("Release") || it.contains("release") }) {
221
+ properties.setProperty("LOCAL_IP", "127.0.0.1") // Production
222
+ properties.setProperty("buildType", "release")
223
+ properties.setProperty("buildOptimisation", "true")
224
+ } else {
225
+ properties.setProperty("LOCAL_IP", getLocalIpAddress()) // Debug
226
+ properties.setProperty("buildType", "debug")
227
+ properties.setProperty("buildOptimisation", "false")
228
+ }
137
229
 
138
- val properties = Properties()
139
- properties.setProperty("LOCAL_IP", getLocalIpAddress())
140
-
141
- // Parse top-level properties
142
- val topLevelRegex = """"([^"]+)"\s*:\s*"([^"]+)"""".toRegex()
143
- webviewConfigContent?.let {
144
- topLevelRegex.findAll(it).forEach { matchResult ->
145
- val (key, value) = matchResult.destructured
146
- if (key != "android") {
147
- properties.setProperty(key, value)
230
+ fun extractProperties(jsonObj: org.json.JSONObject, prefix: String = "") {
231
+ try {
232
+ val keys = jsonObj.keys()
233
+
234
+ while (keys.hasNext()) {
235
+ val key = keys.next()
236
+ val value = jsonObj.opt(key)
237
+ val fullKey = if (prefix.isEmpty()) key else "$prefix.$key"
238
+
239
+ when (value) {
240
+ is org.json.JSONObject -> {
241
+ extractProperties(value, fullKey)
242
+ }
243
+ is org.json.JSONArray -> {
244
+ val arrayValues = (0 until value.length()).map { i ->
245
+ value.opt(i).toString()
246
+ }.joinToString(",")
247
+ properties.setProperty(fullKey, arrayValues)
248
+ }
249
+ else -> {
250
+ properties.setProperty(fullKey, value.toString())
251
+ }
252
+ }
148
253
  }
254
+ } catch (e: Exception) {
255
+ throw RuntimeException("Failed to extract properties from JSON at prefix: $prefix", e)
149
256
  }
150
257
  }
151
258
 
152
- // Parse android object specifically
153
- val androidRegex = """"android"\s*:\s*\{([^}]*)\}""".toRegex()
154
- val androidMatch = androidRegex.find(webviewConfigContent ?: "")
155
- val androidContent = androidMatch?.groupValues?.get(1)
259
+ extractProperties(webviewConfig)
156
260
 
157
- // Parse android object properties
158
- val androidPropsRegex = """"([^"]+)"\s*:\s*"([^"]+)"""".toRegex()
159
- androidContent?.let {
160
- androidPropsRegex.findAll(it).forEach { matchResult ->
161
- val (key, value) = matchResult.destructured
162
- properties.setProperty("android.$key", value)
163
- }
261
+ // Set production-specific properties for release builds
262
+ if (gradle.startParameter.taskNames.any { it.contains("Release") || it.contains("release") }) {
263
+ properties.setProperty("PRODUCTION_URL", "https://yourwebapp.com") // Replace with your domain
264
+ properties.setProperty("apiBaseUrl", "https://api.yourdomain.com/") // Replace with your API URL
164
265
  }
165
266
 
166
267
  // Create the assets directory if it doesn't exist
167
268
  val assetsDir = File("${project.projectDir}/src/main/assets")
168
269
  if (!assetsDir.exists()) {
169
270
  assetsDir.mkdirs()
170
- println("Created assets directory at ${assetsDir.absolutePath}")
171
271
  }
172
272
 
173
273
  // Write to properties file
174
274
  File(assetsDir, "webview_config.properties").outputStream().use {
175
275
  properties.store(it, "WebView Configuration")
176
276
  }
277
+ }
278
+ }
279
+
280
+ // Task to create key store if it doesn't exist
281
+ // Add this task to your build.gradle.kts
282
+ tasks.register("generateKeystore") {
283
+ doLast {
284
+ val keystoreDir = File(project.rootDir, "keystore")
285
+ if (!keystoreDir.exists()) {
286
+ keystoreDir.mkdirs()
287
+ }
177
288
 
178
- println("WebView config generated at ${assetsDir.absolutePath}/webview_config.properties")
289
+ val keystoreFile = File(keystoreDir, "release-key.jks")
290
+ if (!keystoreFile.exists()) {
291
+ val storePass = project.properties["keystorePassword"] as? String ?: System.getenv("KEYSTORE_PASSWORD") ?: "android"
292
+ val keyPass = project.properties["keyPassword"] as? String ?: System.getenv("KEY_PASSWORD") ?: "android"
293
+ val alias = project.properties["keyAlias"] as? String ?: System.getenv("KEY_ALIAS") ?: "release"
294
+
295
+ exec {
296
+ commandLine = listOf(
297
+ "keytool",
298
+ "-genkey",
299
+ "-v",
300
+ "-keystore", keystoreFile.absolutePath,
301
+ "-alias", alias,
302
+ "-keyalg", "RSA",
303
+ "-keysize", "2048",
304
+ "-validity", "10000",
305
+ "-storepass", storePass,
306
+ "-keypass", keyPass,
307
+ "-dname", "CN=YourCompany, OU=YourDepartment, O=YourOrganization, L=YourCity, ST=YourState, C=US"
308
+ )
309
+ }
310
+ println("Generated keystore at: ${keystoreFile.absolutePath}")
311
+ } else {
312
+ println("Keystore already exists at: ${keystoreFile.absolutePath}")
313
+ }
314
+ }
315
+ }
316
+ // Task to build app bundle
317
+ tasks.register("createAppBundle") {
318
+ dependsOn("generateKeystore", "bundleRelease")
319
+ doLast {
320
+ println("""
321
+ =======================================================
322
+ App Bundle created successfully!
323
+
324
+ Location: ${project.buildDir}/outputs/bundle/release/app-release.aab
325
+
326
+ Next steps:
327
+ 1. Test your bundle with:
328
+ bundletool build-apks --bundle=app/build/outputs/bundle/release/app-release.aab --output=test.apks
329
+
330
+ 2. Upload to Play Console: https://play.google.com/console
331
+ =======================================================
332
+ """.trimIndent())
179
333
  }
180
334
  }
@@ -3,26 +3,45 @@
3
3
  xmlns:tools="http://schemas.android.com/tools">
4
4
  <uses-permission android:name="android.permission.INTERNET" />
5
5
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6
+ <uses-permission android:name="android.permission.CAMERA" />
7
+ <uses-permission android:name="android.permission.VIBRATE" />
8
+ <uses-feature android:name="android.hardware.camera" android:required="false" />
9
+ <queries>
10
+ <intent>
11
+ <action android:name="android.media.action.IMAGE_CAPTURE" />
12
+ </intent>
13
+ </queries>
6
14
  <application
7
- android:usesCleartextTraffic="${allowCleartextTraffic}"
8
15
  android:allowBackup="true"
9
16
  android:dataExtractionRules="@xml/data_extraction_rules"
10
17
  android:fullBackupContent="@xml/backup_rules"
18
+ android:hardwareAccelerated="true"
11
19
  android:icon="@mipmap/ic_launcher"
12
20
  android:label="@string/app_name"
13
21
  android:roundIcon="@mipmap/ic_launcher_round"
14
22
  android:supportsRtl="true"
15
23
  android:theme="@style/Theme.AndroidProject"
24
+ android:usesCleartextTraffic="${allowCleartextTraffic}"
16
25
  tools:targetApi="31">
17
26
  <activity
18
- android:name=".MainActivity"
19
- android:exported="true">
27
+ android:name="io.yourname.androidproject.MainActivity"
28
+ android:exported="true"
29
+ android:screenOrientation="portrait">
20
30
  <intent-filter>
21
31
  <action android:name="android.intent.action.MAIN" />
22
32
 
23
33
  <category android:name="android.intent.category.LAUNCHER" />
24
34
  </intent-filter>
25
35
  </activity>
36
+ <provider
37
+ android:name="androidx.core.content.FileProvider"
38
+ android:authorities="io.yourname.androidproject.fileprovider"
39
+ android:exported="false"
40
+ android:grantUriPermissions="true">
41
+ <meta-data
42
+ android:name="android.support.FILE_PROVIDER_PATHS"
43
+ android:resource="@xml/file_paths" />
44
+ </provider>
26
45
  </application>
27
46
 
28
47
  </manifest>