catalyst-core 0.0.3-canary.6 โ†’ 0.0.3-canary.8

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 (44) hide show
  1. package/changelog.md +46 -22
  2. package/dist/native/androidProject/.idea/deploymentTargetSelector.xml +0 -8
  3. package/dist/native/androidProject/.idea/gradle.xml +0 -1
  4. package/dist/native/androidProject/.idea/misc.xml +2 -6
  5. package/dist/native/androidProject/.idea/vcs.xml +0 -2
  6. package/dist/native/androidProject/app/build.gradle.kts +55 -26
  7. package/dist/native/androidProject/app/src/main/AndroidManifest.xml +3 -2
  8. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +54 -0
  9. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +24 -0
  10. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/NativeBridge.kt +261 -204
  11. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/Utils.kt +64 -0
  12. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/BridgeUtils.kt +217 -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/DownloadUtils.kt +251 -0
  15. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FileSizeRouterUtils.kt +347 -0
  16. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FileUtils.kt +334 -0
  17. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/FrameworkServerUtils.kt +362 -0
  18. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/utils/IntentUtils.kt +274 -0
  19. package/dist/native/androidProject/app/src/main/res/drawable/splashscreen_fallback.png +0 -0
  20. package/dist/native/androidProject/app/src/main/res/xml/file_paths.xml +6 -0
  21. package/dist/native/androidProject/gradle/libs.versions.toml +1 -1
  22. package/dist/native/androidProject/gradle/wrapper/gradle-wrapper.properties +1 -1
  23. package/dist/native/bridge/WebBridge.js +42 -2
  24. package/dist/native/bridge/constants/NativeInterfaces.js +22 -0
  25. package/dist/native/bridge/errors.js +39 -0
  26. package/dist/native/bridge/hooks.js +77 -3
  27. package/dist/native/bridge/standardizedHooks.js +80 -0
  28. package/dist/native/bridge/useBaseHook.js +44 -0
  29. package/dist/native/bridge/utils/NativeBridge.js +55 -0
  30. package/dist/native/buildAppAndroid.js +66 -22
  31. package/dist/scripts/loadEnvironmentVariables.js +2 -1
  32. package/dist/sentry.js +2 -0
  33. package/dist/webpack/base.babel.js +1 -1
  34. package/package.json +1 -1
  35. package/dist/native/androidProject/.idea/codeStyles/Project.xml +0 -123
  36. package/dist/native/androidProject/.idea/codeStyles/codeStyleConfig.xml +0 -5
  37. package/dist/native/androidProject/.idea/kotlinc.xml +0 -6
  38. package/dist/native/androidProject/.idea/other.xml +0 -329
  39. package/dist/native/androidProject/app/src/main/assets/webview_config.properties +0 -8
  40. package/dist/native/androidProject/app/src/main/cpp/CMakeLists.txt +0 -41
  41. package/dist/native/androidProject/app/src/main/cpp/native-lib.cpp +0 -22
  42. package/dist/native/iosnativeWebView/iosnativeWebView/ConfigConstants.swift +0 -7
  43. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.xcworkspace/xcuserdata/mayankmahavar.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  44. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/xcuserdata/mayankmahavar.xcuserdatad/xcschemes/xcschememanagement.plist +0 -32
package/changelog.md CHANGED
@@ -1,34 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.3-canary.8] - 2025-01-06
3
4
 
4
- ## [0.0.3-canary.6] - 12-06-2025
5
+ - **App icon configuration**
6
+ - **Splash screen integration**
7
+ - **Url Whitelisting**
5
8
 
9
+ ## [0.0.3-canary.7] - 2025-01-06
6
10
 
7
- This update specifically targets production deployment workflows with:
11
+ ### ๐Ÿš€ Features
8
12
 
9
- โ€ข Automated IP Resolution: No more manual IP configuration for development
10
- โ€ข Streamlined Build Process: One-command builds for both Android and iOS
11
- โ€ข Better Error Handling: More informative error messages and recovery options
12
- โ€ข CLI-First Approach: Enhanced command-line interface for CI/CD integration
13
+ - **Native API Integration**: Enhanced native module integration for better performance
14
+ - **Automated IP Resolution**: Intelligent network detection eliminates manual IP configuration
15
+ - **Universal Build System**: Streamlined one-command builds for both Android and iOS platforms
16
+ - **Enhanced CLI Interface**: Improved command-line tools for better developer experience
13
17
 
14
- ๐Ÿงช Testing & Validation
18
+ ### ๐Ÿ› Bug Fixes
15
19
 
16
- โ€ข โœ… Android Build: Verified APK generation and installation
17
- โ€ข โœ… IP Detection: Tested automatic IP address resolution on macOS
18
- โ€ข โœ… Configuration: Validated dynamic config updates
19
- โ€ข โœ… CLI Operations: Tested enhanced command-line workflows
20
+ - Fixed IP address detection issues on development environments
21
+ - Resolved build configuration conflicts between platforms
22
+ - Improved error handling and recovery mechanisms
20
23
 
21
- ๐Ÿ”„ Breaking Changes
22
- โ€ข None: All changes are backward compatible
23
- โ€ข Enhanced: Existing functionality improved without breaking existing workflows
24
+ ### ๐Ÿ”ง Improvements
24
25
 
25
- ๐Ÿ“ Commit History
26
- โ€ข cc4584e: feat: finishing cli and updating ip address updation
27
- โ€ข 0076d8c: feat: adding cli option and upgrading gradle
26
+ - **Performance**: Optimized native module loading and execution
27
+ - **Developer Experience**: Enhanced CLI with better error messages and debugging info
28
+ - **Configuration**: Dynamic config updates without requiring restarts
29
+ - **Build Process**: Faster and more reliable build pipeline
30
+
31
+ ### ๐Ÿงช Testing & Validation
32
+
33
+ - โœ… **Android Build**: Verified APK generation, installation, and runtime behavior
34
+ - โœ… **iOS Build**: Tested build process and device compatibility
35
+ - โœ… **IP Detection**: Validated automatic network resolution across platforms
36
+ - โœ… **Native Modules**: Confirmed API integration and performance benchmarks
37
+ - โœ… **CLI Operations**: Tested enhanced command-line workflows and error handling
38
+
39
+ ### ๐Ÿ”„ Breaking Changes
40
+
41
+ **None** - All changes maintain backward compatibility while enhancing existing functionality
42
+
43
+ ### ๐Ÿ“ Technical Details
44
+
45
+ - Improved native API bridge for better cross-platform communication
46
+ - Enhanced error reporting with detailed stack traces and suggestions
47
+ - Optimized build configuration for faster development cycles
48
+ - Added comprehensive logging for debugging and monitoring
49
+
50
+ ### ๐Ÿ”— Migration Notes
51
+
52
+ - No migration steps required
53
+ - Existing projects will automatically benefit from improvements
54
+ - Optional: Update CLI usage to leverage new enhanced features
28
55
 
29
- ๐Ÿ”— Related
30
- โ€ข Base Branch: universal_main
31
- โ€ข Target: Production deployment automation
32
- โ€ข Platform: Universal (Android + iOS)
33
56
  ## Version
34
- - Target version: 0.0.3-canary.6
57
+
58
+ - Target version: 0.0.3-canary.7
@@ -4,14 +4,6 @@
4
4
  <selectionStates>
5
5
  <SelectionState runConfigName="app">
6
6
  <option name="selectionMode" value="DROPDOWN" />
7
- <DropdownSelection timestamp="2025-02-18T04:28:14.358379Z">
8
- <Target type="DEFAULT_BOOT">
9
- <handle>
10
- <DeviceId pluginId="PhysicalDevice" identifier="serial=9fbee4f0" />
11
- </handle>
12
- </Target>
13
- </DropdownSelection>
14
- <DialogSelection />
15
7
  </SelectionState>
16
8
  </selectionStates>
17
9
  </component>
@@ -13,7 +13,6 @@
13
13
  <option value="$PROJECT_DIR$/app" />
14
14
  </set>
15
15
  </option>
16
- <option name="resolveExternalAnnotations" value="false" />
17
16
  </GradleProjectSettings>
18
17
  </option>
19
18
  </component>
@@ -1,9 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
1
2
  <project version="4">
2
3
  <component name="ExternalStorageConfigurationManager" enabled="true" />
3
- <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
4
- <output url="file://$PROJECT_DIR$/build/classes" />
5
- </component>
6
- <component name="ProjectType">
7
- <option name="id" value="Android" />
8
- </component>
4
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK" />
9
5
  </project>
@@ -2,7 +2,5 @@
2
2
  <project version="4">
3
3
  <component name="VcsDirectoryMappings">
4
4
  <mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
5
- <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
6
- <mapping directory="$USER_HOME$/catalyst-webview-apps" vcs="Git" />
7
5
  </component>
8
6
  </project>
@@ -1,6 +1,14 @@
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
6
14
  val keystorePassword: String? by project.properties // Changed from keyStorePassword to keystorePassword
@@ -111,6 +119,8 @@ android {
111
119
  excludes.add("**/route-manifest.json.br")
112
120
  excludes.add("META-INF/LICENSE")
113
121
  excludes.add("META-INF/NOTICE")
122
+ excludes.add("META-INF/INDEX.LIST")
123
+ excludes.add("META-INF/io.netty.versions.properties")
114
124
  }
115
125
  }
116
126
 
@@ -131,6 +141,16 @@ dependencies {
131
141
  androidTestImplementation(libs.androidx.espresso.core)
132
142
  implementation("androidx.webkit:webkit:1.12.1")
133
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")
134
154
  }
135
155
 
136
156
  // Task to verify local IP
@@ -185,12 +205,15 @@ tasks.register("generateWebViewConfig") {
185
205
  }
186
206
 
187
207
  val configContent = configJsonFile.readText()
188
-
189
- // Extract WEBVIEW_CONFIG section
190
- val webviewConfigRegex = """"WEBVIEW_CONFIG"\s*:\s*\{([^}]*)\}""".toRegex()
191
- val webviewConfigMatch = webviewConfigRegex.find(configContent)
192
- val webviewConfigContent = webviewConfigMatch?.groupValues?.get(1)
193
-
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
+
194
217
  val properties = Properties()
195
218
 
196
219
  // Set different IP based on build type
@@ -204,30 +227,36 @@ tasks.register("generateWebViewConfig") {
204
227
  properties.setProperty("buildOptimisation", "false")
205
228
  }
206
229
 
207
- // Parse top-level properties
208
- val topLevelRegex = """"([^"]+)"\s*:\s*"([^"]+)"""".toRegex()
209
- webviewConfigContent?.let {
210
- topLevelRegex.findAll(it).forEach { matchResult ->
211
- val (key, value) = matchResult.destructured
212
- if (key != "android") {
213
- 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
+ }
214
253
  }
254
+ } catch (e: Exception) {
255
+ throw RuntimeException("Failed to extract properties from JSON at prefix: $prefix", e)
215
256
  }
216
257
  }
217
258
 
218
- // Parse android object specifically
219
- val androidRegex = """"android"\s*:\s*\{([^}]*)\}""".toRegex()
220
- val androidMatch = androidRegex.find(webviewConfigContent ?: "")
221
- val androidContent = androidMatch?.groupValues?.get(1)
222
-
223
- // Parse android object properties
224
- val androidPropsRegex = """"([^"]+)"\s*:\s*"([^"]+)"""".toRegex()
225
- androidContent?.let {
226
- androidPropsRegex.findAll(it).forEach { matchResult ->
227
- val (key, value) = matchResult.destructured
228
- properties.setProperty("android.$key", value)
229
- }
230
- }
259
+ extractProperties(webviewConfig)
231
260
 
232
261
  // Set production-specific properties for release builds
233
262
  if (gradle.startParameter.taskNames.any { it.contains("Release") || it.contains("release") }) {
@@ -25,7 +25,8 @@
25
25
  tools:targetApi="31">
26
26
  <activity
27
27
  android:name="io.yourname.androidproject.MainActivity"
28
- android:exported="true">
28
+ android:exported="true"
29
+ android:screenOrientation="portrait">
29
30
  <intent-filter>
30
31
  <action android:name="android.intent.action.MAIN" />
31
32
 
@@ -34,7 +35,7 @@
34
35
  </activity>
35
36
  <provider
36
37
  android:name="androidx.core.content.FileProvider"
37
- android:authorities="io.yourname.androidproject.release.fileprovider"
38
+ android:authorities="io.yourname.androidproject.fileprovider"
38
39
  android:exported="false"
39
40
  android:grantUriPermissions="true">
40
41
  <meta-data
@@ -2,6 +2,7 @@ package io.yourname.androidproject
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
+ import android.content.Intent
5
6
  import android.graphics.Bitmap
6
7
  import android.net.Uri
7
8
  import android.os.Bundle
@@ -11,6 +12,8 @@ import android.webkit.*
11
12
  import android.widget.ProgressBar
12
13
  import androidx.webkit.WebViewAssetLoader
13
14
  import io.yourname.androidproject.WebCacheManager
15
+ import io.yourname.androidproject.isUrlAllowed
16
+ import io.yourname.androidproject.isExternalDomain
14
17
  import kotlinx.coroutines.*
15
18
  import java.util.Properties
16
19
 
@@ -34,6 +37,7 @@ class CustomWebView(
34
37
  private var isInitialPageLoaded: Boolean = false
35
38
  private var buildOptimisation: Boolean = false // Added property for build optimization
36
39
  private lateinit var assetLoader: WebViewAssetLoader
40
+ private var allowedUrls: List<String> = emptyList()
37
41
 
38
42
  // Counters for asset loading statistics
39
43
  private var assetLoadAttempts = 0
@@ -56,6 +60,12 @@ class CustomWebView(
56
60
  // Parse buildOptimisation property
57
61
  buildOptimisation = properties.getProperty("buildOptimisation", "false").toBoolean()
58
62
 
63
+ // Load allowed URLs from properties
64
+ allowedUrls = properties.getProperty("accessControl.allowedUrls", "")
65
+ .split(",")
66
+ .map { it.trim() }
67
+ .filter { it.isNotEmpty() }
68
+
59
69
  // Set initial flags based on buildOptimisation
60
70
  if (buildOptimisation) {
61
71
  isInitialApiCalled = false
@@ -71,6 +81,7 @@ class CustomWebView(
71
81
  Log.d(TAG, "Cache Pattern: $cachePatterns")
72
82
  Log.d(TAG, "API Base URL: $apiBaseUrl")
73
83
  Log.d(TAG, "Build Optimisation: $buildOptimisation")
84
+ Log.d(TAG, "Allowed URLs: $allowedUrls")
74
85
  Log.d(TAG, "Initial API Called: $isInitialApiCalled")
75
86
  Log.d(TAG, "Initial Page Loaded: $isInitialPageLoaded")
76
87
  }
@@ -198,6 +209,22 @@ class CustomWebView(
198
209
  }
199
210
  }
200
211
 
212
+
213
+
214
+ private fun openInInAppBrowser(url: String) {
215
+ try {
216
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
217
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
218
+ context.startActivity(intent)
219
+ if (BuildConfig.DEBUG) {
220
+ Log.d(TAG, "๐ŸŒ Opening external URL in in-app browser: $url")
221
+ }
222
+ } catch (e: Exception) {
223
+ Log.e(TAG, "โŒ Failed to open URL in in-app browser: $url", e)
224
+ }
225
+ }
226
+
227
+
201
228
  private fun isApiCall(url: String): Boolean {
202
229
  // Check if URL is an API call based on your API base URL
203
230
  return apiBaseUrl.isNotEmpty() && url.startsWith(apiBaseUrl)
@@ -290,6 +317,25 @@ class CustomWebView(
290
317
  webView.webViewClient = object : WebViewClient() {
291
318
  override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
292
319
  request?.url?.let { url ->
320
+ val urlString = url.toString()
321
+
322
+ // Check if URL is an external domain
323
+ if (url.scheme in listOf("http", "https") && isExternalDomain(urlString, allowedUrls)) {
324
+ if (BuildConfig.DEBUG) {
325
+ Log.d(TAG, "๐ŸŒ External domain detected, opening in in-app browser: $urlString")
326
+ }
327
+ openInInAppBrowser(urlString)
328
+ return true
329
+ }
330
+
331
+ // Check if URL is allowed for internal navigation
332
+ if (!isUrlAllowed(urlString, allowedUrls)) {
333
+ if (BuildConfig.DEBUG) {
334
+ Log.w(TAG, "๐Ÿšซ URL blocked by access control: $urlString")
335
+ }
336
+ return true
337
+ }
338
+
293
339
  // Let WebView handle loading non-API HTTP/HTTPS URLs
294
340
  if (url.scheme in listOf("http", "https")) {
295
341
  return false
@@ -307,6 +353,14 @@ class CustomWebView(
307
353
  Log.d(TAG, "๐Ÿ”„ Intercepting request for: $url on thread: ${Thread.currentThread().name}")
308
354
  }
309
355
 
356
+ if (!isUrlAllowed(url, allowedUrls)) {
357
+ if (BuildConfig.DEBUG) {
358
+ Log.w(TAG, "๐Ÿšซ Network request blocked by access control: $url")
359
+ }
360
+ // Return an empty response to block the request
361
+ return WebResourceResponse("text/plain", "utf-8", null)
362
+ }
363
+
310
364
  // Handle the initial route request - intercept first request regardless of host
311
365
  if (!isInitialApiCalled && request.method == "GET") {
312
366
  isInitialApiCalled = true
@@ -10,6 +10,7 @@ import io.yourname.androidproject.NativeBridge
10
10
  import kotlinx.coroutines.CoroutineScope
11
11
  import kotlinx.coroutines.MainScope
12
12
  import kotlinx.coroutines.cancelChildren
13
+ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
13
14
 
14
15
  class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
15
16
 
@@ -20,6 +21,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
20
21
  private lateinit var properties: Properties
21
22
  private var isHardwareAccelerationEnabled = false
22
23
  private var currentUrl: String = ""
24
+ private var splashStartTime: Long = 0
23
25
 
24
26
  private fun enableHardwareAcceleration() {
25
27
  if (!isHardwareAccelerationEnabled) {
@@ -45,6 +47,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
45
47
  }
46
48
 
47
49
  override fun onCreate(savedInstanceState: Bundle?) {
50
+ val splashScreen = installSplashScreen()
48
51
  super.onCreate(savedInstanceState)
49
52
  if (BuildConfig.DEBUG) {
50
53
  Log.d(TAG, "๐Ÿ“ฑ onCreate started on thread: ${Thread.currentThread().name}")
@@ -63,6 +66,10 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
63
66
  properties.setProperty("buildOptimisation", (!BuildConfig.DEBUG).toString())
64
67
  }
65
68
 
69
+ // Configure splash screen
70
+ splashStartTime = System.currentTimeMillis()
71
+ configureSplashScreen(splashScreen)
72
+
66
73
  // Setup UI
67
74
  binding = ActivityMainBinding.inflate(layoutInflater)
68
75
  supportActionBar?.hide()
@@ -159,4 +166,21 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
159
166
  customWebView.destroy()
160
167
  super.onDestroy()
161
168
  }
169
+
170
+ private fun configureSplashScreen(splashScreen: androidx.core.splashscreen.SplashScreen) {
171
+ val durationProperty = properties.getProperty("splashScreen.duration")
172
+
173
+ splashScreen.setKeepOnScreenCondition {
174
+ val webViewLoaded = ::customWebView.isInitialized &&
175
+ customWebView.getWebView().progress >= 100
176
+
177
+ if (durationProperty != null) {
178
+ val duration = durationProperty.toLong()
179
+ val timeElapsed = System.currentTimeMillis() - splashStartTime >= duration
180
+ !timeElapsed
181
+ } else {
182
+ !webViewLoaded
183
+ }
184
+ }
185
+ }
162
186
  }