@@ -22,91 +22,107 @@ We will try to turn our basic "Hello World" sample into a PWA. Follow these step
2222
2323``` html
2424<!-- /helloworld-pwa.html -->
25- <!DOCTYPE html>
25+ <!DOCTYPE html>
2626<html lang =" en" >
27- <head >
28- <meta charset =" utf-8" />
29- <meta name =" viewport" content =" width=device-width,initial-scale=1.0" />
30- <title >Dynamsoft Barcode Reader PWA Sample - Hello World</title >
31- </head >
32-
33- <body >
34- <h1 >Hello World for PWA</h1 >
35- <div id =" camera-view-container" style =" width : 100% ; height : 80vh " ></div >
36- <br />
37- Results:
38- <div id =" results" style =" width : 100% ; height : 10vh ; overflow : auto " ></div >
39- <script src =" https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader-bundle@11.4.2001/dist/dbr.bundle.js" ></script >
40- <script >
41- if (location .protocol === " file:" ) {
42- const message = ` The page is opened via file:// and our SDKs may not work properly. Please open the page via https:// or host it on "http://localhost/".` ;
43- console .warn (message);
44- alert (message);
45- }
46- </script >
47- <script >
48- /* * LICENSE ALERT - README
49- * To use the library, you need to first specify a license key using the API "initLicense()" as shown below.
50- */
51-
52- Dynamsoft .License .LicenseManager .initLicense (" DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9" );
53-
54- /* *
55- * You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=samples&product=dbr&package=js to get your own trial license good for 30 days.
56- * Note that if you downloaded this sample from Dynamsoft while logged in, the above license key may already be your own 30-day trial license.
57- * For more information, see https://www.dynamsoft.com/barcode-reader/docs/web/programming/javascript/user-guide/index.html?ver=11.4.2001&cVer=true#specify-the-license&utm_source=samples or contact support@dynamsoft.com.
58- * LICENSE ALERT - THE END
59- */
60-
61- // Defined globally for easy debugging.
62- let cameraEnhancer, cvRouter;
63-
64- (async function () {
65- try {
66- // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control.
67- const cameraView = await Dynamsoft .DCE .CameraView .createInstance ();
68- cameraEnhancer = await Dynamsoft .DCE .CameraEnhancer .createInstance (cameraView);
69- document .querySelector (" #camera-view-container" ).append (cameraView .getUIElement ()); // Get default UI and append it to DOM.
70-
71- // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source.
72- cvRouter = await Dynamsoft .CVR .CaptureVisionRouter .createInstance ();
73- cvRouter .setInput (cameraEnhancer);
74-
75- // Define a callback for results.
76- const resultReceiver = new Dynamsoft.CVR.CapturedResultReceiver ();
77- resultReceiver .onDecodedBarcodesReceived = (result ) => {
27+
28+ <head >
29+ <meta charset =" utf-8" />
30+ <meta name =" viewport" content =" width=device-width,initial-scale=1.0" />
31+ <meta name =" description" content =" Read barcodes from camera with Dynamsoft Barcode Reader in a PWA application." />
32+ <meta name =" keywords" content =" barcode, camera, PWA" />
33+ <title >Dynamsoft Barcode Reader PWA Sample - Hello World (Decode via Camera)</title >
34+ </head >
35+
36+ <body >
37+ <h1 >Hello World for PWA</h1 >
38+ <div id =" camera-view-container" style =" width : 100% ; height : 80vh " ></div >
39+ <br />
40+ Results:
41+ <div id =" results" style =" width : 100% ; height : 10vh ; overflow : auto " ></div >
42+ <!-- crossorigin="anonymous" is required for service worker caching. -->
43+ <script crossorigin =" anonymous" src =" https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader-bundle@11.4.2001/dist/dbr.bundle.js" ></script >
44+ <script >
45+ /* * LICENSE ALERT - README
46+ * To use the library, you need to first specify a license key using the API "initLicense()" as shown below.
47+ */
48+
49+ Dynamsoft .License .LicenseManager .initLicense (" DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9" );
50+
51+ /* *
52+ * You can visit https://www.dynamsoft.com/customer/license/trialLicense?utm_source=samples&product=dbr&package=js to get your own trial license good for 30 days.
53+ * Note that if you downloaded this sample from Dynamsoft while logged in, the above license key may already be your own 30-day trial license.
54+ * For more information, see https://www.dynamsoft.com/barcode-reader/docs/web/programming/javascript/user-guide/index.html?ver=11.4.2001&cVer=true#specify-the-license&utm_source=samples or contact support@dynamsoft.com.
55+ * LICENSE ALERT - THE END
56+ */
57+
58+ // Optional. Used to load wasm resources in advance, reducing latency between video playing and barcode decoding.
59+ Dynamsoft .Core .CoreModule .loadWasm ();
60+
61+ // Defined globally for easy debugging.
62+ let cameraEnhancer, cvRouter;
63+
64+ (async () => {
65+ try {
66+ // Create a `CameraEnhancer` instance for camera control and a `CameraView` instance for UI control.
67+ const cameraView = await Dynamsoft .DCE .CameraView .createInstance ();
68+ cameraEnhancer = await Dynamsoft .DCE .CameraEnhancer .createInstance (cameraView);
69+ // Get default UI and append it to DOM.
70+ document .querySelector (" #camera-view-container" ).append (cameraView .getUIElement ());
71+
72+ // Hide the "Powered by Message" overlay on the scanner view
73+ // cameraView.setPowerByMessageVisible(false);
74+
75+ // Create a `CaptureVisionRouter` instance and set `CameraEnhancer` instance as its image source.
76+ cvRouter = await Dynamsoft .CVR .CaptureVisionRouter .createInstance ();
77+ cvRouter .setInput (cameraEnhancer);
78+
79+ // Define a callback for results.
80+ await cvRouter .addResultReceiver ({
81+ onDecodedBarcodesReceived : (result ) => {
82+ if (! result .barcodeResultItems .length ) return ;
83+
84+ const resultsContainer = document .querySelector (" #results" );
85+ resultsContainer .textContent = " " ;
86+ console .log (result);
7887 for (let item of result .barcodeResultItems ) {
79- if (! result .barcodeResultItems .length ) return ;
80-
81- const resultsContainer = document .querySelector (" #results" );
82- resultsContainer .textContent = " " ;
83- console .log (result);
84- for (let item of result .barcodeResultItems ) {
85- resultsContainer .textContent += ` ${ item .formatString } : ${ item .text } \n\n ` ;
86- }
88+ resultsContainer .textContent += ` ${ item .formatString } : ${ item .text } \n\n ` ;
8789 }
88- };
89- cvRouter .addResultReceiver (resultReceiver);
90-
91- // Filter out unchecked and duplicate results.
92- const filter = new Dynamsoft.Utility.MultiFrameResultCrossFilter ();
93- // Filter out unchecked barcodes.
94- filter .enableResultCrossVerification (" barcode" , true );
95- // Filter out duplicate barcodes within 3 seconds.
96- filter .enableResultDeduplication (" barcode" , true );
97- await cvRouter .addResultFilter (filter);
98-
99- // Open camera and start scanning single barcode.
100- await cameraEnhancer .open ();
101- await cvRouter .startCapturing (" ReadSingleBarcode" );
102- } catch (ex) {
103- let errMsg = ex .message || ex;
104- console .error (ex);
105- alert (errMsg);
90+ },
91+ });
92+
93+ // Filter out unchecked and duplicate results.
94+ const filter = new Dynamsoft.Utility.MultiFrameResultCrossFilter ();
95+ // Filter out unchecked barcodes.
96+ filter .enableResultCrossVerification (" barcode" , true );
97+ // Filter out duplicate barcodes within 3 seconds.
98+ filter .enableResultDeduplication (" barcode" , true );
99+ await cvRouter .addResultFilter (filter);
100+
101+ // Open camera and start scanning barcode.
102+ await cameraEnhancer .open ();
103+
104+ if (' disabled' === cameraEnhancer .singleFrameMode ){
105+ // Video played successfully.
106+ cameraView .setScanLaserVisible (true );
107+ }else {
108+ // In iOS PWA, if camera open failed,
109+ // failback to `singleFrameMode = 'camera'`.
110+ // In iOS PWA wasm is slow, so we increase the timeout.
111+ const cvrSettings = await cvRouter .outputSettings (' ReadBarcodes_SpeedFirst' );
112+ cvrSettings .CaptureVisionTemplates [0 ].Timeout = 15000 ;
113+ await cvRouter .initSettings (cvrSettings);
106114 }
107- })();
108- </script >
109- </body >
115+
116+ await cvRouter .startCapturing (" ReadBarcodes_SpeedFirst" );
117+ } catch (ex) {
118+ let errMsg = ex .message || ex;
119+ console .error (ex);
120+ alert (errMsg);
121+ }
122+ })();
123+ </script >
124+ </body >
125+
110126</html >
111127```
112128
@@ -133,44 +149,68 @@ if ('serviceWorker' in navigator) {
133149* Next, create the ` service-worker.js ` file with the following content:
134150
135151``` javascript
136- /* /service-worker.js */
137152// Files to cache
138- const cacheName = ' helloworld-pwa' ;
139- const appShellFiles = [
140- ' ./helloworld-pwa.html' ,
153+ const CACHE_PREFIX = " helloworld-pwa-" ;
154+ const CACHE_NAME = ` ${ CACHE_PREFIX } v1` ;
155+ // Here we choose some files into ASSETS_TO_CACHE to cache.
156+ // You can find these files in "node_modules/dynamsoft-barcode-reader-bundle/dist".
157+ const ASSETS_TO_CACHE = [
158+ " ./helloworld-pwa.html" ,
141159];
142160
143161// Installing Service Worker
144162self .addEventListener (" install" , (e ) => {
145163 console .log (" [Service Worker] Install" );
146164 e .waitUntil (
147- (async () => {
148- const cache = await caches .open (cacheName);
165+ caches .open (CACHE_NAME ).then ((cache ) => {
149166 console .log (" [Service Worker] Caching all: app shell and content" );
150- await cache .addAll (appShellFiles);
151- })()
167+ return cache .addAll (ASSETS_TO_CACHE );
168+ })
169+ );
170+ // Force the waiting service worker to become the active one
171+ self .skipWaiting ();
172+ });
173+
174+ // 2. Activate: Clean up old caches
175+ self .addEventListener (' activate' , (e ) => {
176+ e .waitUntil (
177+ caches .keys ().then ((cacheNames ) => {
178+ return Promise .all (
179+ cacheNames .map ((cacheName ) => {
180+ if (cacheName .startsWith (CACHE_PREFIX ) && cacheName !== CACHE_NAME ) {
181+ console .log (' Deleting old cache:' , cacheName);
182+ return caches .delete (cacheName);
183+ }
184+ })
185+ );
186+ })
152187 );
153188});
154189
155- self .addEventListener (" fetch" , (e ) => {
190+ // 3. Fetch: Stale-While-Revalidate Strategy
191+ self .addEventListener (' fetch' , (e ) => {
156192 e .respondWith (
157- (async () => {
158- // Fetch cached response if exists
159- const cachedResponse = await caches .match (e .request );
160- console .log (` [Service Worker] Fetching resource: ${ e .request .url } ` );
161- if (cachedResponse) {
162- return cachedResponse;
163- }
193+ caches .match (e .request ).then ((cachedResponse ) => {
194+ // Return cached response if found, but fetch a fresh version anyway
195+ const fetchPromise = fetch (e .request ).then ((networkResponse ) => {
196+ if (
197+ ' GET' === e .request .method && networkResponse .ok &&
198+ // Authorization requests should not be cached
199+ ! / https:\/\/ . *? \. dynamsoft. com\/ auth/ .test (e .request .url )
200+ // You can add other filter conditions
201+ ){
202+ // Update the cache with the new version
203+ const clonedRep = networkResponse .clone ();
204+ caches .open (CACHE_NAME ).then ((cache ) => {
205+ cache .put (e .request , clonedRep);
206+ console .log (` [Service Worker] Cache updated: ${ e .request .url } ` );
207+ });
208+ }
209+ return networkResponse;
210+ });
164211
165- // Otherwise, fetch from network
166- const response = await fetch (e .request );
167- const cache = await caches .open (cacheName);
168- console .log (` [Service Worker] Caching new resource: ${ e .request .url } ` );
169- if (e .request .method !== " POST" ) {
170- cache .put (e .request , response .clone ());
171- }
172- return response;
173- })()
212+ return cachedResponse || fetchPromise;
213+ })
174214 );
175215});
176216```
@@ -179,15 +219,6 @@ With the above code, the application can now work offline because the service wo
179219
180220For more information, refer to [ Making PWAs work offline with Service workers] ( https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers ) .
181221
182- > Note:
183- >
184- > Since the files are cached, changes we make in later steps may not be reflected immediately. To ensure updates are applied, clear the cache after changes are made. You can do this by running the following code in the browser console:
185- >
186- > ``` javascript
187- > const cacheName = ' helloworld-pwa' ;
188- > const cache = await caches .delete (cacheName);
189- > ` ` `
190-
191222### Use a web manifest file to make the application installable
192223
193224A web manifest file contains a list of information about a website in JSON format. This information is used to enable the web app to be installed on a device.
@@ -261,38 +292,43 @@ const engineResourcePaths = {
261292};
262293
263294// Files to cache
264- const cacheName = " helloworld-pwa" ;
265- const appShellFiles = [
295+ const CACHE_PREFIX = " helloworld-pwa-" ;
296+ const CACHE_NAME = ` ${ CACHE_PREFIX } v1` ;
297+ // Here we choose some files into ASSETS_TO_CACHE to cache.
298+ // You can find these files in "node_modules/dynamsoft-barcode-reader-bundle/dist".
299+ const ASSETS_TO_CACHE = [
266300 " ./helloworld-pwa.html" ,
267301 " ./dynamsoft-192x192.png" ,
268302 " ./dynamsoft-512x512.png" ,
269303 " ./helloworld-pwa.json" ,
304+ ` ${ engineResourcePaths .dbrBundle } dbr.bundle.js` ,
270305 ` ${ engineResourcePaths .dbrBundle } dbr.bundle.worker.js` ,
271- ` ${ engineResourcePaths .dbrBundle } dynamsoft-capture-vision-bundle.js`
272- ` ${ engineResourcePaths .dbrBundle } dynamsoft-capture-vision-bundle.wasm` ,
273- ` ${ engineResourcePaths .dbrBundle } models/OneDDeblur.data` ,
274- ` ${ engineResourcePaths .dbrBundle } parser-resources/AADHAAR_Map.txt` ,
275- ` ${ engineResourcePaths .dbrBundle } parser-resources/AADHAAR.dcpres` ,
276- ` ${ engineResourcePaths .dbrBundle } parser-resources/AAMVA_DL_ID_WITH_MAG_STRIPE.dcpres` ,
277- ` ${ engineResourcePaths .dbrBundle } parser-resources/AAMVA_DL_ID.dcpres` ,
278- ` ${ engineResourcePaths .dbrBundle } parser-resources/AAMVA_Map.txt` ,
279- ` ${ engineResourcePaths .dbrBundle } parser-resources/GS1_AI_Map.txt` ,
280- ` ${ engineResourcePaths .dbrBundle } parser-resources/GS1_AI.txt` ,
281- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_Map.txt` ,
282- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD1_ID.dcpres` ,
283- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD2_FRENCH_ID.dcpres` ,
284- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD2_ID.dcpres` ,
285- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD2_VISA.dcpres` ,
286- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD3_PASSPORT.dcpres` ,
287- ` ${ engineResourcePaths .dbrBundle } parser-resources/MRTD_TD3_VISA.dcpres` ,
288- ` ${ engineResourcePaths .dbrBundle } parser-resources/SOUTH_AFRICA_DL_Map.txt` ,
289- ` ${ engineResourcePaths .dbrBundle } parser-resources/SOUTH_AFRICA_DL.dcpres` ,
290- ` ${ engineResourcePaths .dbrBundle } parser-resources/VIN_Map.txt` ,
291- ` ${ engineResourcePaths .dbrBundle } parser-resources/VIN.dcpres` ,
306+ ` ${ engineResourcePaths .dbrBundle } dynamsoft-barcode-reader-bundle-ml-simd.js` ,
307+ ` ${ engineResourcePaths .dbrBundle } dynamsoft-barcode-reader-bundle-ml-simd.wasm` ,
308+ ` ${ engineResourcePaths .dbrBundle } models/Code128Decoder.data` ,
309+ ` ${ engineResourcePaths .dbrBundle } models/EAN13Decoder.data` ,
310+ ` ${ engineResourcePaths .dbrBundle } models/Code39ITFDecoder.data` ,
292311 ` ${ engineResourcePaths .dbrBundle } templates/DBR-PresetTemplates.json` ,
293- ` ${ engineResourcePaths .dbrBundle } ui/barcode-scanner.ui.xml` ,
294312 ` ${ engineResourcePaths .dbrBundle } ui/dce.ui.xml` ,
295313 ` ${ engineResourcePaths .dbrBundle } ui/dls.license.dialog.html` ,
314+
315+ // `${engineResourcePaths.dbrBundle}dynamsoft-barcode-reader-bundle.js`,
316+ // `${engineResourcePaths.dbrBundle}dynamsoft-barcode-reader-bundle.wasm`,
317+ // `${engineResourcePaths.dbrBundle}dynamsoft-barcode-reader-bundle-ml-simd-pthread.js`,
318+ // `${engineResourcePaths.dbrBundle}dynamsoft-barcode-reader-bundle-ml-simd-pthread.worker.js`,
319+ // `${engineResourcePaths.dbrBundle}dynamsoft-barcode-reader-bundle-ml-simd-pthread.wasm`,
320+ // `${engineResourcePaths.dbrBundle}models/OneDDeblur.data`,
321+ // `${engineResourcePaths.dbrBundle}models/OneDLocalization.data`,
322+ // `${engineResourcePaths.dbrBundle}models/DataMatrixQRCodeLocalization.data`,
323+ // `${engineResourcePaths.dbrBundle}models/DataMatrixQRCodeDeblur.data`,
324+ // `${engineResourcePaths.dbrBundle}models/PDF417Deblur.data`,
325+ // `${engineResourcePaths.dbrBundle}models/PDF417Localization.data`,
326+ // `${engineResourcePaths.dbrBundle}parser-resources/AADHAAR.data`,
327+ // `${engineResourcePaths.dbrBundle}parser-resources/AAMVA_DL_ID.data`,
328+ // `${engineResourcePaths.dbrBundle}parser-resources/GS1_AI.data`,
329+ // `${engineResourcePaths.dbrBundle}parser-resources/MRTD.data`,
330+ // `${engineResourcePaths.dbrBundle}parser-resources/SOUTH_AFRICA_DL.data`,
331+ // `${engineResourcePaths.dbrBundle}parser-resources/VIN.data`,
296332];
297333```
298334
0 commit comments