cordova-plugin-hot-updates 2.3.0 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cordova-plugin-hot-updates",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Frontend-controlled manual hot updates for Cordova iOS and Android apps using WebView Reload approach. Manual updates only, JavaScript controls all decisions. 100% API compatibility between platforms.",
5
5
  "main": "www/HotUpdates.js",
6
6
  "scripts": {
package/plugin.xml CHANGED
@@ -1,6 +1,6 @@
1
1
  <?xml version='1.0' encoding='utf-8'?>
2
2
  <plugin id="cordova-plugin-hot-updates"
3
- version="2.3.0"
3
+ version="2.3.1"
4
4
  xmlns="http://apache.org/cordova/ns/plugins/1.0"
5
5
  xmlns:android="http://schemas.android.com/apk/res/android">
6
6
 
@@ -88,12 +88,8 @@
88
88
  <source-file src="src/android/HotUpdatesConstants.java"
89
89
  target-dir="src/com/getmeback/hotupdates" />
90
90
 
91
- <!-- Critical preferences for file:// scheme support -->
92
- <config-file target="res/xml/config.xml" parent="/*">
93
- <preference name="scheme" value="file" />
94
- <preference name="AndroidInsecureFileModeEnabled" value="true" />
95
- <preference name="LoadUrlTimeoutValue" value="120000" />
96
- </config-file>
91
+ <!-- AndroidX WebKit for CordovaPluginPathHandler support -->
92
+ <framework src="androidx.webkit:webkit:1.12.+" />
97
93
  </platform>
98
94
 
99
95
  <!-- Plugin hooks (optional) -->
@@ -18,11 +18,16 @@ import android.content.pm.PackageManager;
18
18
  import android.os.Handler;
19
19
  import android.os.Looper;
20
20
  import android.util.Log;
21
+ import android.webkit.MimeTypeMap;
22
+ import android.webkit.WebResourceResponse;
21
23
  import android.webkit.WebSettings;
22
24
  import android.webkit.WebView;
23
25
 
26
+ import androidx.webkit.WebViewAssetLoader;
27
+
24
28
  import org.apache.cordova.CallbackContext;
25
29
  import org.apache.cordova.CordovaPlugin;
30
+ import org.apache.cordova.CordovaPluginPathHandler;
26
31
  import org.json.JSONArray;
27
32
  import org.json.JSONException;
28
33
  import org.json.JSONObject;
@@ -88,23 +93,6 @@ public class HotUpdates extends CordovaPlugin {
88
93
 
89
94
  canaryHandler = new Handler(Looper.getMainLooper());
90
95
 
91
- // Enable file access for WebView (needed for loading from files/www)
92
- try {
93
- Object engineView = webView.getView();
94
- if (engineView instanceof WebView) {
95
- WebView wv = (WebView) engineView;
96
- WebSettings settings = wv.getSettings();
97
- settings.setAllowFileAccess(true);
98
- settings.setAllowContentAccess(true);
99
- // Note: These are deprecated but needed for file:// access
100
- settings.setAllowFileAccessFromFileURLs(true);
101
- settings.setAllowUniversalAccessFromFileURLs(true);
102
- Log.d(TAG, "WebView file access enabled");
103
- }
104
- } catch (Exception e) {
105
- Log.w(TAG, "Could not configure WebView settings: " + e.getMessage());
106
- }
107
-
108
96
  loadConfiguration();
109
97
  loadIgnoreList();
110
98
  loadVersionHistory();
@@ -140,28 +128,8 @@ public class HotUpdates extends CordovaPlugin {
140
128
  @Override
141
129
  public void onStart() {
142
130
  super.onStart();
143
-
144
- // If there's an installed version, redirect to external storage on startup
145
- // This ensures pending updates that were auto-installed will be loaded
146
- String installedVersion = getPrefs().getString(PREF_INSTALLED_VERSION, null);
147
- if (installedVersion != null) {
148
- cordova.getActivity().runOnUiThread(() -> {
149
- try {
150
- String indexPath = "file://" + wwwPath + "/" + INDEX_HTML;
151
- Log.d(TAG, "Redirecting to external storage: " + indexPath);
152
-
153
- // Clear cache and disable caching before redirect
154
- android.webkit.WebView androidWebView = (android.webkit.WebView) webView.getView();
155
- androidWebView.clearCache(true);
156
- WebSettings webSettings = androidWebView.getSettings();
157
- webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
158
-
159
- webView.loadUrlIntoView(indexPath, false);
160
- } catch (Exception e) {
161
- Log.e(TAG, "Failed to redirect to external storage: " + e.getMessage());
162
- }
163
- });
164
- }
131
+ // No redirect needed - PathHandler transparently serves from files/www
132
+ // when an installed version exists, or falls through to assets/www otherwise
165
133
  }
166
134
 
167
135
  @Override
@@ -173,6 +141,77 @@ public class HotUpdates extends CordovaPlugin {
173
141
  super.onDestroy();
174
142
  }
175
143
 
144
+ // ============================================================
145
+ // PathHandler - serve updated files via https://localhost/
146
+ // ============================================================
147
+
148
+ @Override
149
+ public CordovaPluginPathHandler getPathHandler() {
150
+ WebViewAssetLoader.PathHandler handler = path -> {
151
+ try {
152
+ // Only intercept if there's an installed version
153
+ String installedVersion = getPrefs().getString(PREF_INSTALLED_VERSION, null);
154
+ if (installedVersion == null) {
155
+ return null; // Let Cordova serve from assets/www
156
+ }
157
+
158
+ File wwwDir = new File(wwwPath);
159
+ if (!wwwDir.exists()) {
160
+ return null;
161
+ }
162
+
163
+ if (path.isEmpty()) {
164
+ path = INDEX_HTML;
165
+ }
166
+
167
+ File file = new File(wwwDir, path);
168
+
169
+ // Security: prevent path traversal
170
+ if (!file.getCanonicalPath().startsWith(wwwDir.getCanonicalPath())) {
171
+ Log.e(TAG, "Path traversal attempt blocked: " + path);
172
+ return null;
173
+ }
174
+
175
+ if (!file.exists() || file.isDirectory()) {
176
+ return null; // Fall through to Cordova default handler
177
+ }
178
+
179
+ String mimeType = getMimeType(path);
180
+ InputStream is = new FileInputStream(file);
181
+ return new WebResourceResponse(mimeType, null, is);
182
+
183
+ } catch (Exception e) {
184
+ Log.e(TAG, "PathHandler error: " + e.getMessage());
185
+ return null;
186
+ }
187
+ };
188
+
189
+ return new CordovaPluginPathHandler(handler);
190
+ }
191
+
192
+ private String getMimeType(String path) {
193
+ if (path.endsWith(".js") || path.endsWith(".mjs")) {
194
+ return "application/javascript";
195
+ } else if (path.endsWith(".wasm")) {
196
+ return "application/wasm";
197
+ } else if (path.endsWith(".html") || path.endsWith(".htm")) {
198
+ return "text/html";
199
+ } else if (path.endsWith(".css")) {
200
+ return "text/css";
201
+ } else if (path.endsWith(".json")) {
202
+ return "application/json";
203
+ } else if (path.endsWith(".svg")) {
204
+ return "image/svg+xml";
205
+ }
206
+
207
+ String extension = MimeTypeMap.getFileExtensionFromUrl("file:///" + path);
208
+ if (extension != null) {
209
+ String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
210
+ if (mime != null) return mime;
211
+ }
212
+ return "application/octet-stream";
213
+ }
214
+
176
215
  // ============================================================
177
216
  // Configuration
178
217
  // ============================================================
@@ -812,29 +851,23 @@ public class HotUpdates extends CordovaPlugin {
812
851
  private void reloadWebView() {
813
852
  cordova.getActivity().runOnUiThread(() -> {
814
853
  try {
815
- // Get WebView and its settings
816
854
  android.webkit.WebView androidWebView = (android.webkit.WebView) webView.getView();
817
855
  WebSettings webSettings = androidWebView.getSettings();
818
856
 
819
- // Aggressively clear all WebView caches BEFORE reload
820
- androidWebView.clearCache(true); // Clear cache including disk files
857
+ // Clear cache to force fresh load from PathHandler
858
+ androidWebView.clearCache(true);
821
859
  androidWebView.clearHistory();
822
- androidWebView.clearFormData();
823
860
  webView.clearCache(true);
824
861
  webView.clearHistory();
825
-
826
- // Disable caching completely to force fresh load
827
862
  webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
828
863
 
829
- Log.d(TAG, "WebView cache, history and form data cleared");
830
-
831
- String indexPath = "file://" + wwwPath + "/" + INDEX_HTML;
832
- Log.d(TAG, "Reloading WebView with: " + indexPath);
864
+ // Always use https://localhost/ - PathHandler serves from files/www
865
+ String hostname = preferences.getString("hostname", "localhost");
866
+ String reloadUrl = "https://" + hostname + "/" + INDEX_HTML;
833
867
 
834
- // Load new content directly into WebView (like CHCP does)
835
- webView.loadUrlIntoView(indexPath, false);
868
+ Log.d(TAG, "Reloading WebView: " + reloadUrl);
869
+ webView.loadUrlIntoView(reloadUrl, false);
836
870
 
837
- Log.d(TAG, "WebView reloaded successfully");
838
871
  } catch (Exception e) {
839
872
  Log.e(TAG, "Failed to reload WebView: " + e.getMessage());
840
873
  }
@@ -53,7 +53,6 @@ public final class HotUpdatesConstants {
53
53
  public static final String PREF_VERSION_HISTORY = "hot_updates_version_history";
54
54
  public static final String PREF_CANARY_VERSION = "hot_updates_canary_version";
55
55
  public static final String PREF_DOWNLOAD_IN_PROGRESS = "hot_updates_download_in_progress";
56
- public static final String PREF_PENDING_UPDATE_URL = "hot_updates_pending_update_url";
57
56
  public static final String PREF_PENDING_UPDATE_READY = "hot_updates_pending_ready";
58
57
 
59
58
  // ============================================================