Skip to content

Commit 2e04df3

Browse files
Merge pull request #209 from appdevforall/feat/ADFA-4708-pdfjs-dual-version
ADFA-4708: serve pdf.js v6+v4 with a manifest so the app routes per device
2 parents 17a495d + 039ad00 commit 2e04df3

4 files changed

Lines changed: 106 additions & 54 deletions

File tree

‎iiab-android‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -621,15 +621,18 @@ mkdir -p /library/www/html/pdfjs
621621
# curl/unzip in the build environment. pdf.js release cadence ~monthly (semver; majors
622622
# can break) -> the version is PINNED in fetch-pdfjs.sh; bump it deliberately, mainly on
623623
# a pdf.js security advisory, not on every release.
624-
if [ ! -d "${K2GO_OPT_DIR}/static/pdfjs/dist/web" ]; then
625-
log "Fetching pinned pdf.js dist (build-time)..."
624+
if [ ! -f "${K2GO_OPT_DIR}/static/pdfjs/dist/manifest.json" ]; then
625+
log "Fetching pinned pdf.js builds (build-time)..."
626626
if ! bash "${K2GO_OPT_DIR}/static/pdfjs/fetch-pdfjs.sh"; then
627627
warn "pdf.js fetch failed; viewer will 404 until the dist is provided."
628628
fi
629629
fi
630-
if [ -d "${K2GO_OPT_DIR}/static/pdfjs/dist/web" ]; then
630+
# Clean teardown before redeploy: wipe the served dir so a removed build leaves no stale
631+
# files (removing a build is just dropping it from VERSIONS in fetch-pdfjs.sh).
632+
rm -rf /library/www/html/pdfjs/*
633+
if [ -f "${K2GO_OPT_DIR}/static/pdfjs/dist/manifest.json" ]; then
631634
cp -a "${K2GO_OPT_DIR}/static/pdfjs/dist/." /library/www/html/pdfjs/
632-
ok "pdf.js dist deployed."
635+
ok "pdf.js builds deployed: $(sed -n 's/.*\"id\":\"\([^\"]*\)\".*/\1/p' /library/www/html/pdfjs/manifest.json | tr '\n' ' ')"
633636
else
634637
warn "pdf.js dist not found; viewer will 404 until deployed."
635638
fi

‎static/pdfjs/README.md‎

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,45 @@
1-
# pdf.js viewer (ADFA-4708) — in-WebView PDF viewing
1+
# pdf.js viewers (ADFA-4708) — in-WebView PDF viewing
22

33
The Android System WebView has no built-in PDF viewer, so a PDF served by the box would
44
otherwise be ignored (or downloaded). This module serves Mozilla **pdf.js** from the local
55
nginx so the portal WebView can render PDFs inline and offline.
66

7-
## How it works
8-
- Served at `http://localhost:8085/pdfjs/` (see `pdfjs-nginx.conf`).
9-
- The app routes an internal-host PDF to `…/pdfjs/web/viewer.html?file=<encoded pdf url>`
10-
(see `PdfPolicy` / `PdfViewerUrl` in the controller app). Same origin as the box's PDFs,
11-
so there is no CORS / mixed-content problem and it works with no internet.
12-
- pdf.js is pure JavaScript (Apache-2.0) — the same dist serves ARM 32- and 64-bit.
7+
## Why multiple builds
8+
We never modify the device ROM, so the System WebView is whatever the device ships/updates
9+
to. A modern WebView runs the latest pdf.js; a frozen/old one does not. So we ship more than
10+
one pinned build and let the **app pick per device**, driven by `manifest.json`:
11+
12+
- **v6** — needs Chromium/WebView ≥ 118 (latest; receives upstream security fixes).
13+
- **v4** — needs Chromium/WebView ≥ 88 (best-effort for old/frozen devices; **tentative**).
14+
15+
Devices below the lowest build simply fall back to downloading the PDF — nothing breaks.
16+
17+
## Layout (produced by fetch-pdfjs.sh, deployed to /library/www/html/pdfjs)
18+
```
19+
/pdfjs/manifest.json # {schema, builds:[{id,viewerPath,minWebViewMajor,version,tentative}]}
20+
/pdfjs/6/web/viewer.html # pdf.js v6
21+
/pdfjs/4/web/viewer.html # pdf.js v4
22+
```
23+
The app reads the manifest and routes a PDF to the best build:
24+
`/pdfjs/<id>/web/viewer.html?file=<encoded pdf url>`.
1325

1426
## Assets (dist)
15-
The prebuilt pdf.js distribution is fetched at rootfs-build time, not vendored in git:
27+
The prebuilt distributions are fetched at rootfs-build time, not vendored in git:
28+
29+
./fetch-pdfjs.sh # writes ./dist/<id>/ + ./dist/manifest.json
1630

17-
PDFJS_VERSION=4.10.38 ./fetch-pdfjs.sh # writes ./dist (web/ + build/)
31+
Pin versions in the `VERSIONS` table at the top of `fetch-pdfjs.sh`. pdf.js is pure JS
32+
(Apache-2.0) → one set of files serves ARM 32- and 64-bit.
1833

19-
Pin `PDFJS_VERSION` (and optionally `PDFJS_SHA256`) to the release we ship. The extracted
20-
`dist/` is deployed to `/library/www/html/pdfjs/` so `/pdfjs/web/viewer.html` resolves.
34+
## Removing a build (e.g. drop v4 by policy: maintained software only)
35+
The app is **data-driven** off the manifest — there is no version-specific app code. To
36+
remove a build cleanly (full teardown, no stale files or dead code):
37+
1. Delete its line from `VERSIONS` in `fetch-pdfjs.sh`.
38+
2. Rebuild. The installer wipes `/library/www/html/pdfjs` before redeploying, so the removed
39+
build disappears, the manifest no longer lists it, and the app stops routing to it.
40+
Devices that relied on it fall back to downloading the PDF.
2141

22-
## Build / rootfs
23-
The `iiab-android` setup script installs `pdfjs-nginx.conf` into the :8085 server and
24-
deploys the dist to the web root (same mechanism as the other static modules). All editions.
42+
## Update cadence
43+
pdf.js ships a stable dist ~monthly and uses semver (a **major** bump can break the viewer
44+
API). Keep versions **pinned** and bump deliberately — primarily on a pdf.js **security
45+
advisory**, not on every release.

‎static/pdfjs/fetch-pdfjs.sh‎

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,66 @@
11
#!/usr/bin/env bash
2-
# Fetch a pinned Mozilla pdf.js prebuilt distribution into ./dist for deployment.
3-
# pdf.js is pure JS (Apache-2.0) -> no 32/64-bit concern; the same dist serves every ABI.
4-
# Run at rootfs-build time on a networked host; the extracted dist is then deployed to
5-
# /library/www/html/pdfjs (see the iiab-android setup script).
2+
# Fetch pinned Mozilla pdf.js prebuilt distributions into ./dist and emit a manifest the
3+
# app reads to pick a viewer per device. pdf.js is pure JS (Apache-2.0) -> ABI-agnostic
4+
# (one set of files serves ARM 32 and 64). Run at rootfs-build time on a networked host.
5+
#
6+
# WHY TWO VERSIONS: the Android System WebView is whatever the device has (we never touch
7+
# the ROM). A modern WebView runs the latest pdf.js; a frozen/old one does not. So we ship
8+
# a newer build AND an older build, and the app routes by the device's WebView major:
9+
# - v6 -> needs Chromium/WebView >= 118 (latest; receives upstream security fixes)
10+
# - v4 -> needs Chromium/WebView >= 88 (best-effort for old/frozen devices; TENTATIVE)
11+
# The app is data-driven off manifest.json, so REMOVING a build is just deleting its row
12+
# from VERSIONS below: it won't be fetched, won't be in the manifest, and the app ignores
13+
# it — no dead code, no stale files (the installer wipes the web dir before redeploying).
14+
#
15+
# To drop v4 later (e.g. policy: maintained software only): delete its VERSIONS line. Done.
616
set -euo pipefail
717

8-
# Pinned pdf.js version. pdf.js ships a stable dist ~monthly and uses semver, so a MAJOR
9-
# bump can break the viewer API. Keep this pinned and bump it DELIBERATELY — primarily when
10-
# a pdf.js security advisory lands (it has had RCE CVEs), not on every release. Also confirm
11-
# the pin runs on the oldest Android System WebView we target (app minSdk = 24 / Android 7;
12-
# recent pdf.js majors need a modern Chromium WebView). Use the newest STABLE that is still
13-
# compatible — never a nightly/beta.
14-
# TODO(Luis): confirm the version to ship (marker below is a placeholder, not verified).
15-
PDFJS_VERSION="${PDFJS_VERSION:-4.10.38}"
16-
# Optional integrity check: set PDFJS_SHA256 to the expected zip checksum to enforce it.
17-
PDFJS_SHA256="${PDFJS_SHA256:-}"
18+
# id : version : minWebViewMajor : [flags]
19+
# - id = served subdir and manifest id (/pdfjs/<id>/web/viewer.html)
20+
# - version = pinned pdf.js release (CONFIRM before shipping)
21+
# - minWebViewMajor = minimum Chromium/WebView major that build supports
22+
# - flags = optional, comma-separated (e.g. "tentative")
23+
VERSIONS=(
24+
"6:6.1.200:118:"
25+
"4:4.10.38:88:tentative"
26+
)
1827

1928
HERE="$(cd "$(dirname "$0")" && pwd)"
2029
DIST_DIR="${HERE}/dist"
21-
ZIP_URL="https://github.com/mozilla/pdf.js/releases/download/v${PDFJS_VERSION}/pdfjs-${PDFJS_VERSION}-dist.zip"
22-
TMP_ZIP="$(mktemp -t pdfjs-XXXXXX.zip)"
23-
trap 'rm -f "$TMP_ZIP"' EXIT
30+
rm -rf "$DIST_DIR"
31+
mkdir -p "$DIST_DIR"
2432

25-
echo "Fetching pdf.js v${PDFJS_VERSION} ..."
26-
curl -fSL "$ZIP_URL" -o "$TMP_ZIP"
33+
manifest_rows=()
34+
for row in "${VERSIONS[@]}"; do
35+
IFS=':' read -r id version minmajor flags <<< "$row"
36+
zip_url="https://github.com/mozilla/pdf.js/releases/download/v${version}/pdfjs-${version}-dist.zip"
37+
tmp_zip="$(mktemp -t "pdfjs-${id}-XXXXXX.zip")"
38+
echo "Fetching pdf.js v${version} (build '${id}', min WebView ${minmajor}) ..."
39+
curl -fSL "$zip_url" -o "$tmp_zip"
40+
mkdir -p "${DIST_DIR}/${id}"
41+
unzip -q "$tmp_zip" -d "${DIST_DIR}/${id}"
42+
rm -f "$tmp_zip"
43+
test -f "${DIST_DIR}/${id}/web/viewer.html" \
44+
|| { echo "ERROR: web/viewer.html missing for build '${id}'"; exit 1; }
45+
tentative="false"; [ "${flags:-}" = "tentative" ] && tentative="true"
46+
manifest_rows+=(" {\"id\":\"${id}\",\"viewerPath\":\"/pdfjs/${id}/web/viewer.html\",\"minWebViewMajor\":${minmajor},\"version\":\"${version}\",\"tentative\":${tentative}}")
47+
done
2748

28-
if [ -n "$PDFJS_SHA256" ]; then
29-
echo "${PDFJS_SHA256} ${TMP_ZIP}" | sha256sum -c -
30-
fi
49+
# Emit manifest.json from exactly what was fetched.
50+
{
51+
echo '{'
52+
echo ' "schema": "pdfjs-viewers-v1",'
53+
echo ' "builds": ['
54+
n=${#manifest_rows[@]}
55+
for i in "${!manifest_rows[@]}"; do
56+
sep=","; [ "$i" -eq "$((n-1))" ] && sep=""
57+
echo "${manifest_rows[$i]}${sep}"
58+
done
59+
echo ' ]'
60+
echo '}'
61+
} > "${DIST_DIR}/manifest.json"
3162

32-
rm -rf "$DIST_DIR"
33-
mkdir -p "$DIST_DIR"
34-
unzip -q "$TMP_ZIP" -d "$DIST_DIR"
35-
# Sanity: the viewer the app points to must exist.
36-
test -f "${DIST_DIR}/web/viewer.html" || { echo "ERROR: web/viewer.html missing from dist"; exit 1; }
37-
echo "pdf.js dist ready at ${DIST_DIR} (web/viewer.html present)."
63+
echo "pdf.js dist ready:"
64+
ls -1 "$DIST_DIR"
65+
echo "--- manifest.json ---"
66+
cat "${DIST_DIR}/manifest.json"

‎static/pdfjs/pdfjs-nginx.conf‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
# Mozilla pdf.js viewer (ADFA-4708) — static assets served directly by nginx on :8085.
2-
# Enables viewing PDFs INSIDE the portal WebView (which has no built-in PDF viewer):
3-
# the app routes a PDF to http://localhost:8085/pdfjs/web/viewer.html?file=<pdf url>.
4-
# Same origin as the box's own PDFs, so it works fully offline (no CORS / mixed-content).
5-
#
6-
# Unlike k2go-docs this is infrastructure that is ALWAYS present (not hidden-until-content):
7-
# the viewer must resolve for the feature to work. The dist ships web/ and build/ at the root.
1+
# Mozilla pdf.js viewers (ADFA-4708) — static assets served on :8085.
2+
# Enables viewing PDFs INSIDE the portal WebView (which has no built-in PDF viewer).
3+
# Multiple pinned builds live under /pdfjs/<id>/ (e.g. /pdfjs/6/, /pdfjs/4/); the app reads
4+
# /pdfjs/manifest.json and routes a PDF to the best build for the device's WebView version:
5+
# http://localhost:8085/pdfjs/<id>/web/viewer.html?file=<pdf url>
6+
# Same origin as the box's PDFs, so it works fully offline (no CORS / mixed-content).
7+
# Always present (not hidden-until-content): the viewer must resolve for the feature to work.
88
location ^~ /pdfjs/ {
99
alias /library/www/html/pdfjs/;
1010
autoindex off;
11-
index web/viewer.html;
1211
}

0 commit comments

Comments
 (0)