Reloader
More control over hot code push reloading for your mobile apps. A replacement
for mdg:reload-on-resume
with more options and better UX.
Before using this package we recommend that you understand what Hot Code Push is, you can learn all about it here
We provide two ways for you to handle your app code updates:
- Always reload
- Reload when the app allows (recommended)
Always reload
You don't need to configure anything, your app is going to reload as soon as the code is received.
If you want you can inform launchScreenDelay
(0 by default) in milliseconds to
hold your splashscreen longer, avoiding a flash when the app is starting and
reloading.
1"public": { 2 "packages": { 3 "quave:reloader": { 4 "launchScreenDelay": 200 5 } 6 } 7}
Reload when the app allows
We recommend this method as with it you can control when your app is going to reload. You can even delegate this decision to the final user.
In this case you must use automaticInitialization
as false
in your settings.
1"public": { 2 "packages": { 3 "quave:reloader": { 4 "automaticInitialization": false 5 } 6 } 7}
You also need to call
Reloader.initialize
in the render or initialization of your app providing a function (can be async) in the property beforeReload
.
Installing
meteor add quave:reloader meteor remove mdg:reload-on-resume
Configuration Options
idleCutoff
Default: 1000 * 60 * 5 // 5 minutes
How long (in ms) can an app be idle before we consider it a start and not a
resume. Applies only when check: 'everyStart'
. Set to 0
to never check on
resume.
launchScreenDelay
Default: 0
How long the splash screen will be visible. It's useful to avoid your app being rendered just for a few milliseconds and then refreshing.
automaticInitialization
Default: true
If you want to initialize the reloader
yourself you need to turn
off automaticInitialization
. This is useful when you want to provide code to
some callback as this is not possible using JSON initialization.
You can provide your callbacks calling Reloader.initialize(), for example:
1ReloaderCordova.initialize({ 2 beforeReload(ok, nok) { 3 const isOkToReload = confirm('Your app will load now, ok?'); 4 if (isOkToReload) { 5 ok(); 6 return; 7 } 8 nok(); 9 }, 10});
Example with React
File: Routes.js
(where we render the routes)
1 2export const Routes = () => { 3 useEffect(() => initializeReloader(), []); 4 5 return ( 6 <Switch> 7 // React router routes... 8 </Switch> 9 ); 10}
File: initializeReloader.js
1import { Reloader } from 'meteor/quave:reloader'; 2import { loggerClient } from 'meteor/quave:logs/loggerClient'; 3import { showConfirm } from './ConfirmationDialog'; 4import { methodCall } from '../../methods/methodCall'; 5import { version } from '../../version'; 6 7export const initializeReloader = () => { 8 loggerClient.info({ message: 'initializeReloader' }); 9 Reloader.initialize({ 10 async beforeReload(updateApp, holdAppUpdate) { 11 loggerClient.info({ message: 'initializeReloader beforeReload' }); 12 let appUpdateData = {}; 13 try { 14 appUpdateData = 15 (await methodCall('getAppUpdateData', { clientVersion: version })) || 16 {}; 17 } catch (e) { 18 loggerClient.info({ 19 message: 'forcing app reload because getAppUpdateData is breaking', 20 }); 21 updateApp(); 22 return; 23 } 24 loggerClient.info({ 25 message: 'initializeReloader beforeReload appUpdateData', 26 appUpdateData, 27 }); 28 if (appUpdateData.ignore) { 29 loggerClient.info({ 30 message: 31 'initializeReloader beforeReload appUpdateData ignore is true', 32 appUpdateData, 33 }); 34 return; 35 } 36 const cancelAction = appUpdateData.forceUpdate 37 ? updateApp 38 : holdAppUpdate; 39 try { 40 const message = appUpdateData.forceUpdate 41 ? 'Precisamos atualizar o aplicativo. É rapidinho!' 42 : 'Deseja atualizar agora? É rapidinho!'; 43 const result = await showConfirm({ 44 autoFocus: false, 45 title: appUpdateData.title || 'Atualização disponível', 46 content: appUpdateData.message || message, 47 confirmText: appUpdateData.actionLabel || 'Beleza', 48 cancelText: appUpdateData.noActionLabel || 'Mais tarde', 49 hideCancel: !!appUpdateData.forceUpdate, 50 dismiss: cancelAction, 51 onCancel() { 52 loggerClient.info({ 53 message: 'initializeReloader beforeReload onCancel', 54 appUpdateData, 55 }); 56 cancelAction(); 57 }, 58 }); 59 loggerClient.info({ 60 message: `initializeReloader beforeReload showConfirm result is ${result}`, 61 appUpdateData, 62 }); 63 if (result) { 64 loggerClient.info({ 65 message: 'initializeReloader beforeReload showConfirm ok', 66 appUpdateData, 67 }); 68 updateApp(); 69 return; 70 } 71 loggerClient.info({ 72 message: 'initializeReloader beforeReload showConfirm nok', 73 appUpdateData, 74 }); 75 cancelAction(); 76 } catch (e) { 77 loggerClient.info({ 78 message: 'initializeReloader beforeReload showConfirm catch call nok', 79 appUpdateData, 80 }); 81 cancelAction(); 82 } 83 }, 84 }); 85}; 86
File: getAppUpdateData.js
1import { Meteor } from 'meteor/meteor'; 2import { logger } from 'meteor/quave:logs/logger'; 3import { AppUpdatesCollection } from '../db/AppUpdatesCollection'; 4import { version } from '../version'; 5 6Meteor.methods({ 7 getAppUpdateData({ clientVersion } = {}) { 8 this.unblock(); 9 10 if (Meteor.isClient) return null; 11 12 const appUpdate = AppUpdatesCollection.findOne() || {}; 13 14 const result = { 15 ...appUpdate, 16 ...(appUpdate.ignoreVersions && 17 appUpdate.ignoreVersions.length && 18 appUpdate.ignoreVersions.includes(version) 19 ? { ignore: true } 20 : {}), 21 version, 22 }; 23 logger.info({ 24 message: `getAppUpdateData clientVersion=${clientVersion}, newClientVersion=${version}, ${JSON.stringify( 25 result 26 )}`, 27 appUpdateData: appUpdate, 28 appUpdateResult: result, 29 clientVersion, 30 }); 31 return result; 32 }, 33}); 34