cordova-plugin-crosswire-sword 0.2.9 → 0.2.11
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/RELEASENOTES.md +12 -0
- package/libs/android/arm64-v8a/libsword.so +0 -0
- package/libs/android/armeabi-v7a/libsword.so +0 -0
- package/libs/android/x86/libsword.so +0 -0
- package/libs/android/x86_64/libsword.so +0 -0
- package/libs/ios/SWORD.xcframework/ios-arm64/libSWORD.a +2 -2
- package/libs/ios/SWORD.xcframework/ios-arm64-simulator/libSWORD.a +2 -2
- package/package.json +1 -1
- package/plugin.xml +1 -3
- package/src/android/SWORD.java +45 -4
- package/src/android/SafStorage.java +66 -2
- package/src/ios/SWORD.swift +568 -67
- package/www/SWORD.js +31 -3
- package/libs/ios/curl.xcframework/Info.plist +0 -47
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/curl.h +0 -3373
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/curlver.h +0 -77
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/easy.h +0 -123
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/header.h +0 -74
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/mprintf.h +0 -85
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/multi.h +0 -560
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/options.h +0 -70
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/stdcheaders.h +0 -35
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/system.h +0 -399
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/typecheck-gcc.h +0 -964
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/urlapi.h +0 -156
- package/libs/ios/curl.xcframework/ios-arm64/Headers/curl/websockets.h +0 -98
- package/libs/ios/curl.xcframework/ios-arm64/libcurl-all.a +0 -0
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/curl.h +0 -3373
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/curlver.h +0 -77
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/easy.h +0 -123
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/header.h +0 -74
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/mprintf.h +0 -85
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/multi.h +0 -560
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/options.h +0 -70
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/stdcheaders.h +0 -35
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/system.h +0 -399
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/typecheck-gcc.h +0 -964
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/urlapi.h +0 -156
- package/libs/ios/curl.xcframework/ios-arm64-simulator/Headers/curl/websockets.h +0 -98
- package/libs/ios/curl.xcframework/ios-arm64-simulator/libcurl-all.a +0 -0
package/RELEASENOTES.md
CHANGED
|
@@ -20,6 +20,18 @@
|
|
|
20
20
|
-->
|
|
21
21
|
# Release Notes
|
|
22
22
|
|
|
23
|
+
### 0.2.11 (Oct 1, 2026)
|
|
24
|
+
* Study data (bookmarks and, in time, notes) in a folder of the user's choosing, named sword-studydata so several devices and SWORD apps can share it (doc/bookmarks-format.md in Bishop): a picked folder holding bookmarks/, or itself named sword-studydata, is used as it is, otherwise sword-studydata/ is made inside it
|
|
25
|
+
* iOS: the study-data folder may be in iCloud Drive or any app's folder; where a provider grants files but no folder (Google Drive), the bookmark files are picked in place (SWMgr_chooseDataFiles) or Bishop's own are saved there and opened once (SWMgr_exportDataFiles); a provider's file is rewritten in place so it keeps its identity
|
|
26
|
+
* Android: a cloud provider's stale record of a replaced file is refreshed before the retry by name
|
|
27
|
+
* initSWORD answers `features` ({ dataStorage, dataFiles, sharedStorage, bibleSync }) so the page can offer what the platform has; SWORD.js keeps it as SWORD.features
|
|
28
|
+
* iOS: HTTPUtils_makeRequest takes the method codes SWORD.js defines (METHOD_GET is 0) and no longer crashes on a bad URL; a user agent naming the app, device and engine; sharing a verse through the system share sheet; passive FTP and verified peers set in InstallMgr.conf
|
|
29
|
+
|
|
30
|
+
### 0.2.10 (Sep 26, 2026)
|
|
31
|
+
* iOS: HTTP(S) through Apple's NSURLSession; no curl or OpenSSL in the app, so App Store Connect's export-compliance questions do not arise (only Apple's encryption)
|
|
32
|
+
* Android: a cloud folder (Google Drive) whose provider is still loading is waited for instead of being taken as empty, a listing that fails is reported to the page, and a file another device replaced is found again by name; the app no longer creates a second personal.conf beside the real one
|
|
33
|
+
* FTP without curl (iOS): EPSV first and PASV's advertised address ignored, as curl does, so sources such as STEP answer; failures are reported as with curl, so file-by-file installs proceed on sources without packages
|
|
34
|
+
|
|
23
35
|
### 0.2.9 (Sep 25, 2026)
|
|
24
36
|
* BibleSync works: biblesync 2.2.0 with the Android and Apple interface discovery sent upstream; Android holds a Wi-Fi multicast lock while it runs (CHANGE_WIFI_MULTICAST_STATE); every speaker in the room is heard, not only the first
|
|
25
37
|
* Android: a sword:// or bible:// link the app is opened with reaches the page as handleOpenURL, exactly as cordova-ios does, on a cold start and a warm one
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/libs/ios/SWORD.xcframework/ios-arm64/libSWORD.a
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 37229112 bytes
|
|
4
|
+
sha256: 3e031f0b4dbd6b3c5096cadf56adca793363d9d4bb40ad0810e79e2d2d4e7260
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/libs/ios/SWORD.xcframework/ios-arm64-simulator/libSWORD.a
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 37272016 bytes
|
|
4
|
+
sha256: d4a361c089cb1384d15fce6755470d9d3bd012d8acf7af69ba27315ea4f71ae8
|
package/package.json
CHANGED
package/plugin.xml
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
xmlns:rim="http://www.blackberry.com/ns/widgets"
|
|
5
5
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
6
6
|
id="cordova-plugin-crosswire-sword"
|
|
7
|
-
version="0.2.
|
|
7
|
+
version="0.2.11">
|
|
8
8
|
<name>cordova-plugin-crosswire-sword</name>
|
|
9
9
|
<description>The SWORD Project Plugin</description>
|
|
10
10
|
<license>GNU 2.0</license>
|
|
@@ -137,13 +137,11 @@
|
|
|
137
137
|
<header-file src="src/ios/SWORD-Bridging-Header.h" type="BridgingHeader" />
|
|
138
138
|
<source-file src="src/ios/SWORD.swift" />
|
|
139
139
|
<framework src="libs/ios/SWORD.xcframework" custom="true" embed="false" />
|
|
140
|
-
<framework src="libs/ios/curl.xcframework" custom="true" embed="false" />
|
|
141
140
|
<framework src="libc++.tbd" />
|
|
142
141
|
<framework src="libz.tbd" />
|
|
143
142
|
<framework src="libicucore.tbd" />
|
|
144
143
|
<framework src="Security.framework" />
|
|
145
144
|
<framework src="CoreFoundation.framework" />
|
|
146
|
-
<framework src="SystemConfiguration.framework" />
|
|
147
145
|
|
|
148
146
|
<!-- <source-file src="lib/ios/libSWORD.a" framework="true" /> -->
|
|
149
147
|
</platform>
|
package/src/android/SWORD.java
CHANGED
|
@@ -40,6 +40,7 @@ import org.json.JSONException;
|
|
|
40
40
|
import org.json.JSONObject;
|
|
41
41
|
|
|
42
42
|
import org.crosswire.android.sword.SWMgr;
|
|
43
|
+
import org.crosswire.android.sword.SafStorage;
|
|
43
44
|
import org.crosswire.android.sword.AndroidMgr;
|
|
44
45
|
import org.crosswire.android.sword.SWModule;
|
|
45
46
|
import org.crosswire.android.sword.InstallMgr;
|
|
@@ -52,6 +53,8 @@ import android.net.wifi.WifiManager;
|
|
|
52
53
|
import android.app.Activity;
|
|
53
54
|
|
|
54
55
|
public class SWORD extends CordovaPlugin {
|
|
56
|
+
// the app-neutral study-data folder (see SWMgr_getDataPath)
|
|
57
|
+
public static final String STUDY_DATA_FOLDER = "sword-studydata";
|
|
55
58
|
// held while BibleSync runs: without it most Wi-Fi drivers filter out the multicast group
|
|
56
59
|
private WifiManager.MulticastLock multicastLock = null;
|
|
57
60
|
public static final String TAG = "SWORD";
|
|
@@ -228,6 +231,15 @@ public class SWORD extends CordovaPlugin {
|
|
|
228
231
|
if (action.equals("initSWORD")) {
|
|
229
232
|
JSONObject r = new JSONObject();
|
|
230
233
|
r.put("version", mgr.version());
|
|
234
|
+
// what the page may offer on Android (SWORD.features): a shared
|
|
235
|
+
// module library and a study-data folder, both picked as SAF trees;
|
|
236
|
+
// no picking of single files (a tree grant covers any provider)
|
|
237
|
+
JSONObject features = new JSONObject();
|
|
238
|
+
features.put("sharedStorage", true);
|
|
239
|
+
features.put("dataStorage", true);
|
|
240
|
+
features.put("dataFiles", false);
|
|
241
|
+
features.put("bibleSync", true);
|
|
242
|
+
r.put("features", features);
|
|
231
243
|
callbackContext.success(r);
|
|
232
244
|
}
|
|
233
245
|
else if (action.equals("echo")) {
|
|
@@ -635,9 +647,19 @@ Log.d(TAG, "SWModule_getRenderChapter");
|
|
|
635
647
|
else callbackContext.error("couldn't write: " + args.getString(0));
|
|
636
648
|
}
|
|
637
649
|
else if (action.equals("SWMgr_listDir")) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
650
|
+
// off the WebView thread: a cloud folder's provider may take
|
|
651
|
+
// seconds to finish loading, and the listing waits for it
|
|
652
|
+
final String path = args.getString(0);
|
|
653
|
+
cordova.getThreadPool().execute(new Runnable() { public void run() {
|
|
654
|
+
JSONArray r = new JSONArray();
|
|
655
|
+
for (String s : mgr.listDir(path)) r.put(s);
|
|
656
|
+
// a shared or data folder whose provider failed or never finished
|
|
657
|
+
// loading answers an empty listing natively; the page must know
|
|
658
|
+
SWMgr.SharedStorage ds = mgr.getDataStorage(), ss = mgr.getSharedStorage();
|
|
659
|
+
boolean failed = (ds instanceof SafStorage && ((SafStorage) ds).lastListFailed) || (ss instanceof SafStorage && ((SafStorage) ss).lastListFailed);
|
|
660
|
+
if (failed) callbackContext.error("couldn't list: " + path);
|
|
661
|
+
else callbackContext.success(r);
|
|
662
|
+
}});
|
|
641
663
|
}
|
|
642
664
|
else if (action.equals("SWMgr_removeFile")) {
|
|
643
665
|
if (mgr.removeFile(args.getString(0))) callbackContext.success();
|
|
@@ -685,7 +707,26 @@ Log.d(TAG, "SWModule_getRenderChapter");
|
|
|
685
707
|
callbackContext.success(label);
|
|
686
708
|
}
|
|
687
709
|
else if (action.equals("SWMgr_getDataPath")) {
|
|
688
|
-
|
|
710
|
+
// study data lives in an app-neutral folder named sword-studydata
|
|
711
|
+
// (bookmarks/ inside it, later notes and the like), so several
|
|
712
|
+
// devices and several SWORD apps can share one. Decided by what
|
|
713
|
+
// the picked folder holds, not by its name (a provider can report
|
|
714
|
+
// a name from before a rename for a while): a folder which already
|
|
715
|
+
// has bookmarks/ at its root IS the study-data folder, and so is one
|
|
716
|
+
// named sword-studydata (just created to be it, so still empty);
|
|
717
|
+
// otherwise sword-studydata/ inside it, existing or made on the
|
|
718
|
+
// first write. The provider is asked, so off the WebView thread.
|
|
719
|
+
cordova.getThreadPool().execute(new Runnable() { public void run() {
|
|
720
|
+
String path = mgr.getDataPath();
|
|
721
|
+
SWMgr.SharedStorage ds = mgr.getDataStorage();
|
|
722
|
+
if (ds instanceof SafStorage && path.startsWith("/sword-data")) {
|
|
723
|
+
SafStorage saf = (SafStorage) ds;
|
|
724
|
+
SWMgr.FileInfo root = saf.stat("bookmarks");
|
|
725
|
+
boolean isIt = (root != null && root.isDirectory) || STUDY_DATA_FOLDER.equals(saf.rootName());
|
|
726
|
+
if (!isIt) path += STUDY_DATA_FOLDER + "/";
|
|
727
|
+
}
|
|
728
|
+
callbackContext.success(path);
|
|
729
|
+
}});
|
|
689
730
|
}
|
|
690
731
|
else if (action.equals("SWMgr_getDataStorage")) {
|
|
691
732
|
// the separately chosen study-data folder, or "" if study data lives beside the library
|
|
@@ -33,6 +33,7 @@ import android.content.ContentResolver;
|
|
|
33
33
|
import android.content.Context;
|
|
34
34
|
import android.database.Cursor;
|
|
35
35
|
import android.net.Uri;
|
|
36
|
+
import android.os.Bundle;
|
|
36
37
|
import android.os.ParcelFileDescriptor;
|
|
37
38
|
import android.provider.DocumentsContract;
|
|
38
39
|
import android.provider.DocumentsContract.Document;
|
|
@@ -74,6 +75,8 @@ public class SafStorage implements SWMgr.SharedStorage {
|
|
|
74
75
|
private final Map<Integer, Staged> staged = new HashMap<Integer, Staged>();
|
|
75
76
|
// relative path -> document id, learned from listings and creations
|
|
76
77
|
private final Map<String, String> docIds = new HashMap<String, String>();
|
|
78
|
+
// how long a first listing of a cloud folder may keep loading before we take what there is
|
|
79
|
+
private static final long LIST_WAIT_MILLIS = 15000, LIST_POLL_MILLIS = 250;
|
|
77
80
|
|
|
78
81
|
public SafStorage(Context context, Uri treeUri) {
|
|
79
82
|
this.stagingDir = new java.io.File(context.getCacheDir(), "saf-staging");
|
|
@@ -86,6 +89,12 @@ public class SafStorage implements SWMgr.SharedStorage {
|
|
|
86
89
|
|
|
87
90
|
public Uri getTreeUri() { return treeUri; }
|
|
88
91
|
|
|
92
|
+
/** the picked folder's own name as the provider reports it, or null */
|
|
93
|
+
public String rootName() {
|
|
94
|
+
SWMgr.FileInfo info = queryOne(docUri(treeDocId));
|
|
95
|
+
return (info == null || info.name == null || info.name.length() == 0) ? null : info.name;
|
|
96
|
+
}
|
|
97
|
+
|
|
89
98
|
/** true if we still hold a grant for the tree and it is reachable */
|
|
90
99
|
public boolean isAvailable() {
|
|
91
100
|
return stat("") != null;
|
|
@@ -159,7 +168,30 @@ public class SafStorage implements SWMgr.SharedStorage {
|
|
|
159
168
|
String prefix = (dirPath.length() == 0) ? "" : dirPath + "/";
|
|
160
169
|
Cursor c = null;
|
|
161
170
|
try {
|
|
162
|
-
|
|
171
|
+
// a cloud provider (Google Drive) answers the first query on a folder
|
|
172
|
+
// it has not fetched yet with a partial, often empty, cursor flagged
|
|
173
|
+
// EXTRA_LOADING: taking that as the folder's contents made Bishop
|
|
174
|
+
// think a bookmarks file was absent and create a second one. Ask
|
|
175
|
+
// again until the provider says it is done, within reason.
|
|
176
|
+
long deadline = System.currentTimeMillis() + LIST_WAIT_MILLIS;
|
|
177
|
+
while (true) {
|
|
178
|
+
c = resolver.query(childrenUri, COLUMNS, null, null, null);
|
|
179
|
+
if (c == null) break;
|
|
180
|
+
Bundle extras = c.getExtras();
|
|
181
|
+
String error = (extras == null) ? null : extras.getString(DocumentsContract.EXTRA_ERROR);
|
|
182
|
+
if (error != null) {
|
|
183
|
+
Log.w(TAG, "list failed for " + dirPath + ": provider says " + error);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
boolean loading = extras != null && extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
|
|
187
|
+
if (!loading) break;
|
|
188
|
+
if (System.currentTimeMillis() > deadline) {
|
|
189
|
+
Log.w(TAG, "list of " + dirPath + " still loading after " + LIST_WAIT_MILLIS + " ms: not trusting it");
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
c.close(); c = null;
|
|
193
|
+
try { Thread.sleep(LIST_POLL_MILLIS); } catch (InterruptedException e) { break; }
|
|
194
|
+
}
|
|
163
195
|
if (c != null) {
|
|
164
196
|
while (c.moveToNext()) {
|
|
165
197
|
SWMgr.FileInfo info = fromCursor(c);
|
|
@@ -191,6 +223,32 @@ public class SafStorage implements SWMgr.SharedStorage {
|
|
|
191
223
|
|
|
192
224
|
@Override
|
|
193
225
|
public int open(String path, String mode, boolean create) {
|
|
226
|
+
int fd = openResolved(path, mode, create);
|
|
227
|
+
if (fd >= 0) return fd;
|
|
228
|
+
// the id we had may be stale: another device can replace a file
|
|
229
|
+
// under the same name (a cloud provider gives it a new id); forget
|
|
230
|
+
// what we knew and look the name up once more
|
|
231
|
+
String known;
|
|
232
|
+
synchronized (this) { known = docIds.get(path); }
|
|
233
|
+
if (known == null) return fd;
|
|
234
|
+
forget(path);
|
|
235
|
+
// ask the provider to refresh what it knows about the file and its
|
|
236
|
+
// folder (a cloud provider's local record can lag a change made on
|
|
237
|
+
// the web or on another device) before the name is looked up again
|
|
238
|
+
try {
|
|
239
|
+
resolver.refresh(docUri(known), null, null);
|
|
240
|
+
String parentId = resolve(parentOf(path));
|
|
241
|
+
if (parentId != null) resolver.refresh(DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, parentId), null, null);
|
|
242
|
+
}
|
|
243
|
+
catch (Exception e) {
|
|
244
|
+
Log.i(TAG, "refresh not honoured for " + path + ": " + e);
|
|
245
|
+
}
|
|
246
|
+
forget(path);
|
|
247
|
+
Log.i(TAG, "retrying " + path + " by name after a failed open");
|
|
248
|
+
return openResolved(path, mode, create);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private int openResolved(String path, String mode, boolean create) {
|
|
194
252
|
String id = resolve(path);
|
|
195
253
|
if (id == null) {
|
|
196
254
|
if (!create) return -1;
|
|
@@ -301,12 +359,18 @@ public class SafStorage implements SWMgr.SharedStorage {
|
|
|
301
359
|
return info;
|
|
302
360
|
}
|
|
303
361
|
|
|
362
|
+
/** set when the last list() could not be trusted (the provider failed or
|
|
363
|
+
* never finished loading): native code sees only an empty listing, and
|
|
364
|
+
* the app must not take that for an empty folder */
|
|
365
|
+
public volatile boolean lastListFailed = false;
|
|
366
|
+
|
|
304
367
|
@Override
|
|
305
368
|
public SWMgr.FileInfo[] list(String path) {
|
|
369
|
+
lastListFailed = false;
|
|
306
370
|
String id = resolve(path);
|
|
307
371
|
if (id == null) return null;
|
|
308
372
|
List<SWMgr.FileInfo> entries = listChildren(path, id);
|
|
309
|
-
if (entries == null) return null;
|
|
373
|
+
if (entries == null) { lastListFailed = true; return null; }
|
|
310
374
|
return entries.toArray(new SWMgr.FileInfo[entries.size()]);
|
|
311
375
|
}
|
|
312
376
|
|