Skip to content

Commit

Permalink
Merge pull request #1 from quavedev/version-2-clean-up
Browse files Browse the repository at this point in the history
  • Loading branch information
filipenevola authored Oct 20, 2020
2 parents 9b1a698 + 864c305 commit 87f52b5
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .versions
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ [email protected]
[email protected]
[email protected]
[email protected]
quave:[email protected].1
quave:[email protected].2
quave:[email protected]
[email protected]
[email protected]
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# Changelog

## 2.0.2 - 2020-10-19
### New feature
You can control from your app code when your app should update.

### Clean up
We removed options that we don't believe are necessary, read more details [here](./README.md)

## 1.6.0 - 2020-06-12
### Config using Meteor.settings
- Config now is set using `Meteor.settings.public.packages.reloader` object
Expand Down
292 changes: 183 additions & 109 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,129 +1,85 @@
# Reloader

## 2.0 introduced the ability for the app to control the reload. Readme will be updated soon.
More control over hot code push reloading for your mobile apps. A replacement
for [`mdg:reload-on-resume`](https://github.com/meteor/mobile-packages/blob/master/packages/mdg:reload-on-resume/README.md)
with more options and better UX.

More control over hot code push reloading for your mobile apps. A replacement for [`mdg:reload-on-resume`](https://github.com/meteor/mobile-packages/blob/master/packages/mdg:reload-on-resume/README.md) 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](https://guide.meteor.com/hot-code-push.html)

As of Meteor 1.3, if you prevent instant reloading on updates, the newest version of the code will be used on your app's next cold start - no reload necessary. This can be achieved with `Reloader.configure({check: false, refresh: 'start'})`. However, you can also:
We provide two ways for you to handle your app code updates:

- Reload on resume, to update to the newest version of the code when the app is returned from the background: see [`refresh`](#refresh) (the launch screen is put back up during such reloads to hide the white screen you get with `mdg:reload-on-resume`)
- On start or resume, leave the launch screen up and wait to see whether there is an update available: see [`check`](#check), [`checkTimer`](#checktimer), and [`idleCutoff`](#idlecutoff)
- Delay removal of the launch screen, to hide the white screen that appears at the beginning of a reload: see [`launchScreenDelay`](#launchscreendelay)
- Always reload
- Reload when the app allows (recommended)

### Contents
### Always reload

- [Options](#options)
- [check](#check)
- [checkTimer](#checktimer)
- [refresh](#refresh)
- [idleCutoff](#idlecutoff)
- [launchScreenDelay](#launchscreendelay)
- [automaticInitialization](#automaticInitialization)
- [Helpers](#helpers)
- [Reloader.updateAvailable.get()](#reloaderupdateavailableget)
- [Reloader.reload()](#reloaderreload)
- [Development](#development)
- [Run tests](#run-tests)
- [Credits](#credits)
You don't need to configure anything, your app is going to reload as soon as the
code is received.

### Installation
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.

```sh
meteor add quave:reloader
meteor remove mdg:reload-on-resume
```json
"public": {
"packages": {
"quave:reloader": {
"launchScreenDelay": 200
}
}
}
```

If you have any calls to `location.reload()` or `location.replace(location.href)` in your app, replace them with `Reloader.reload()`.

## Options

The default options are shown below. You can override them in your settings.

```js
const DEFAULT_OPTIONS = {
check: 'everyStart',
checkTimer: 0,
refresh: 'startAndResume',
idleCutoff: 1000 * 60 * 5, // 5 minutes
launchScreenDelay: 100,
};
```
### Reload when the app allows

These default options will make sure that your app is up to date every time a user starts your app, or comes back to it after 5 minutes of being idle.
We recommend this method as with it you can control when you are app is going to
reload. You can even delegate this decision to the final user.

Another popular configuration is:
In this case you must use `automaticInitialization` as `false` in your settings.

```json
{
"public":
"packages": {
"quave:reloader": {
"check": "firstStart",
"checkTimer": 5000,
"refresh": "start"
}
"public": {
"packages": {
"quave:reloader": {
"automaticInitialization": false
}
}
}
```

This will make sure the first time your app is run it is up to date, will download new versions of code while the app is being used, and then only update when the app is next started.

You can have a different configuration for development just using a different settings.

### check

When to make additional checks for new code bundles. The app splash screen is shown during the check. Possible values are:

- `everyStart` (default): Check every time the app starts. Does not include resuming the app, unless the `idleCutOff` has been reached.
- `firstStart`: Check only the first time the app starts (just after downloading it).
- `false`: Never make additional checks and rely purely on code bundles being downlaoded in the background while the app is being used.

### checkTimer

Default: `3000`
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`.

How long to wait (in ms) when making additional checks for new file bundles. In future versions of Meteor we will have an API to instantly check if an update is available or not, but until then we need to simply wait to see if a new code bundle is downloaded. Depending on the size of your app bundle and the phone's connection speed, the default three seconds may not be enough - you can increase it if you find that you have new code immediately after starting the app.
## Installing

### refresh

When to refresh to the latest code bundle if one finished downloading after the end of the `check` period. The app splash screen is shown during the refresh. Possible values are:
```sh
meteor add quave:reloader
meteor remove mdg:reload-on-resume
```

- `startAndResume` (default): Refresh to the latest bundle both when starting and resuming the app.
- `start`: Refresh only when the app is started (not resumed).
- `instantly`: Overrides everything else. If set, your app will have similar behaviour to the default in Meteor, with code updates being refreshed immeidately. The only improvement/difference is that the app's splash screen is displayed during the refresh.
## Configuration Options

### idleCutoff

Default: `1000 * 60 * 10 // 10 minutes`
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.
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

**Planned option for future version. Currently not configurable.**

Default: `100`
Default: `0`

How long to wait (in ms) after reload before hiding the launch screen. The goal is to leave it up until your page has finished rendering, so the user does not see a blank white screen. The duration will vary based on your app's render time and the speed of the device. To be more precise, set `launchScreenDelay` to 0 and release the launch screen yourself when the page has rendered. For example, if the only two pages that might be displayed on reload are `index` and `post`, then you would do:

```javascript
launchScreenHandle = Launchscreen.hold();

Template.index.onRendered(() => {
launchScreenHandle.release();
});

Template.post.onRendered(() => {
launchScreenHandle.release();
});
```

Or if you have a layout template, you could put a single `.release()` in that template's `onRendered`.
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

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.
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:

Expand All @@ -140,28 +96,146 @@ ReloaderCordova.initialize({
});
```

## Helpers

These helpers can help you to have an "Update Now" button.

### A note about using these helpers

Some people have reported having their app rejected during the Apple review process for having an "Update Now" button or similar as opposed to using the refresh on resume behavior that this package provides by default. If you really want to have an update button when new code is available, make sure you don't push any new code to the server until after your app has been approved. But it's probably safer/better to simply not have an update button at all!

### How to use them anyway
## Example with React

#### Reloader.updateAvailable.get()
File: `Routes.js` (where we render the routes)
```javascript

`Reloader.updateAvailable` is a reactive variable that returns true when an update has been downloaded.
export const Routes = () => {
useEffect(() => initializeReloader(), []);

```js
ReloaderCordova.updateAvailable.get(); // Reactively returns true if an update is ready
return (
<Switch>
// React router routes...
</Switch>
);
}
```

#### Reloader.reload()
File: `initializeReloader.js`
```javascript
import { Reloader } from 'meteor/quave:reloader';
import { loggerClient } from 'meteor/quave:logs/loggerClient';
import { showConfirm } from './ConfirmationDialog';
import { methodCall } from '../../methods/methodCall';
import { version } from '../../version';

export const initializeReloader = () => {
loggerClient.info({ message: 'initializeReloader' });
Reloader.initialize({
async beforeReload(updateApp, holdAppUpdate) {
loggerClient.info({ message: 'initializeReloader beforeReload' });
let appUpdateData = {};
try {
appUpdateData =
(await methodCall('getAppUpdateData', { clientVersion: version })) ||
{};
} catch (e) {
loggerClient.info({
message: 'forcing app reload because getAppUpdateData is breaking',
});
updateApp();
return;
}
loggerClient.info({
message: 'initializeReloader beforeReload appUpdateData',
appUpdateData,
});
if (appUpdateData.ignore) {
loggerClient.info({
message:
'initializeReloader beforeReload appUpdateData ignore is true',
appUpdateData,
});
return;
}
const cancelAction = appUpdateData.forceUpdate
? updateApp
: holdAppUpdate;
try {
const message = appUpdateData.forceUpdate
? 'Precisamos atualizar o aplicativo. É rapidinho!'
: 'Deseja atualizar agora? É rapidinho!';
const result = await showConfirm({
autoFocus: false,
title: appUpdateData.title || 'Atualização disponível',
content: appUpdateData.message || message,
confirmText: appUpdateData.actionLabel || 'Beleza',
cancelText: appUpdateData.noActionLabel || 'Mais tarde',
hideCancel: !!appUpdateData.forceUpdate,
dismiss: cancelAction,
onCancel() {
loggerClient.info({
message: 'initializeReloader beforeReload onCancel',
appUpdateData,
});
cancelAction();
},
});
loggerClient.info({
message: `initializeReloader beforeReload showConfirm result is ${result}`,
appUpdateData,
});
if (result) {
loggerClient.info({
message: 'initializeReloader beforeReload showConfirm ok',
appUpdateData,
});
updateApp();
return;
}
loggerClient.info({
message: 'initializeReloader beforeReload showConfirm nok',
appUpdateData,
});
cancelAction();
} catch (e) {
loggerClient.info({
message: 'initializeReloader beforeReload showConfirm catch call nok',
appUpdateData,
});
cancelAction();
}
},
});
};

Call `Reloader.reload()` to refresh the page.
```

### Credits
File: `getAppUpdateData.js`
```javascript
import { Meteor } from 'meteor/meteor';
import { logger } from 'meteor/quave:logs/logger';
import { AppUpdatesCollection } from '../db/AppUpdatesCollection';
import { version } from '../version';

Meteor.methods({
getAppUpdateData({ clientVersion } = {}) {
this.unblock();

if (Meteor.isClient) return null;

const appUpdate = AppUpdatesCollection.findOne() || {};

const result = {
...appUpdate,
...(appUpdate.ignoreVersions &&
appUpdate.ignoreVersions.length &&
appUpdate.ignoreVersions.includes(version)
? { ignore: true }
: {}),
version,
};
logger.info({
message: `getAppUpdateData clientVersion=${clientVersion}, newClientVersion=${version}, ${JSON.stringify(
result
)}`,
appUpdateData: appUpdate,
appUpdateResult: result,
clientVersion,
});
return result;
},
});

thanks to @jamielob and @martijnwalraven for his help with this package (forks)!
```
2 changes: 1 addition & 1 deletion package.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package.describe({
name: 'quave:reloader',
version: '2.0.1',
version: '2.0.2',
summary: 'More control over hot code push reloading',
git: 'https://github.com/quavedev/reloader/',
});
Expand Down
Loading

0 comments on commit 87f52b5

Please sign in to comment.