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.
|
|
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.
|
|
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
|
-
<!--
|
|
92
|
-
<
|
|
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
|
-
//
|
|
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
|
-
//
|
|
820
|
-
androidWebView.clearCache(true);
|
|
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
|
-
|
|
830
|
-
|
|
831
|
-
String
|
|
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
|
-
|
|
835
|
-
webView.loadUrlIntoView(
|
|
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
|
// ============================================================
|