Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Meta PR: Implement offline support #1239

Merged
merged 92 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
b9f9ba6
feat: Add react-native modules for PouchDB
Ldoppea May 22, 2024
26b7613
feat: Configure PouchDB to run on the project
Ldoppea May 28, 2024
2adeb50
feat: Add cozy-pouch-link module
Ldoppea May 28, 2024
f3fcb04
feat: Configure CozyClient to use CozyPouchLink
Ldoppea May 31, 2024
509711e
feat: Configure CozyClient to also use StackLink (when online)
Ldoppea May 31, 2024
6224bf1
feat: Add PouchDBFind plugin to the PouchDB configuration
Ldoppea May 31, 2024
c50ada9
feat: Add clientCachedStorage to handle CozyClient's requests cache
Ldoppea Jul 11, 2024
f14949f
feat: Cache `/apps/:slug/open` request for offline support
Ldoppea Jul 11, 2024
b5caa41
feat: Upgrade cozy-intent to `2.23.0`
Ldoppea Sep 24, 2024
ba477b8
feat: Implement FlagshipLinkRequest interface through localMethods
Ldoppea Jul 30, 2024
5eb7cf1
feat: Enable CacheMode for CozyProxyWebView on android when offline
Ldoppea Jul 11, 2024
96e14fb
feat: Ignore queries warmup on PouchLink
Ldoppea Jul 30, 2024
3e9f251
feat: Declare schemas into cozy-client instance
Ldoppea Jul 26, 2024
3022913
feat: Add react-native-mail plugin
Ldoppea Jul 26, 2024
6357c9d
feat: Allow to send Pouch databases through email for debug purpose
Ldoppea Jul 26, 2024
7b9e8d1
feat: Declare offline support in cozy-apps injected metadata
Ldoppea Jul 30, 2024
3137ff1
feat: Prevent local PouchDB modification to be replicated to remote DB
Ldoppea Sep 13, 2024
b6e541d
feat: Add `downloadFile` in localMethods and handle offline files
Ldoppea Aug 8, 2024
9e09d1f
feat: Make import files automatically available offline
Ldoppea Aug 8, 2024
9992198
feat: Clean non-important offline files when too old
Ldoppea Aug 8, 2024
aab3773
feat: Use NetStatusBoundary only when logged out
Ldoppea Aug 22, 2024
ab4cefd
fix: Set correct return objects for `getIndexHtmlForSlug`
Ldoppea Aug 22, 2024
727a877
feat: Enable offline mode only for cozy-home and mespapiers
Ldoppea Aug 22, 2024
d8edf9d
feat: Display an error message when opening unsupported offline cozy-app
Ldoppea Aug 22, 2024
219d1b3
feat: Enable HttpServer on iOS when offline
Ldoppea Aug 22, 2024
0884962
feat: Open cozy-app when offline only if it supports Offline mode
Ldoppea Sep 13, 2024
b002fc6
docs: Document how to make a cozy-app compatible with Offline mode
Ldoppea Sep 13, 2024
4be8483
refactor: Handle SendDb deeplink in its own hook
Ldoppea Sep 15, 2024
a05ec48
feat: Allow to reset local PouchDB using UniversalLinks
Ldoppea Sep 15, 2024
cd046f7
feat: Display an error dialog when trying to download a file offline
Ldoppea Sep 24, 2024
86233c9
feat: Allow cozy-apps to verify if offline file downloading is available
Ldoppea Sep 24, 2024
5607e73
fix: Skip io.cozy.jobs queries
Ldoppea Sep 24, 2024
805980c
docs: Document how to debug Offline mode
Ldoppea Sep 24, 2024
020505b
docs: Update docs' table of content
Ldoppea Sep 24, 2024
6f30521
fix: Upload DB files to the Cozy instead of sending them by email
Ldoppea Oct 1, 2024
0546ada
fix: Remove unused plugin rn-fetch-blob
Ldoppea Oct 1, 2024
152e672
feat: Upgrade cozy-pouch-link to `49.1.0`
Ldoppea Oct 3, 2024
ce60fbc
feat: Upgrade cozy-client and cozy-pouch-link
Ldoppea Dec 20, 2024
7390221
feat: Add react-native-performance module
Ldoppea Nov 20, 2024
6e8e1da
feat: Add performance measurements
Ldoppea Sep 26, 2024
1133872
feat: Upgrade cozy-client and cozy-pouch-link to `51.7.0`
Ldoppea Dec 20, 2024
47a507d
feat: Enable performances measurements to CozyClient and links
Ldoppea Dec 18, 2024
574674f
feat: Add performances measurements to Redux package
Ldoppea Dec 4, 2024
308a38f
feat: Allow to send Performance logs through email for debug purpose
Ldoppea Nov 25, 2024
cec9848
feat: Change file name format when sending PouchDB files by email
Ldoppea Dec 4, 2024
206f81e
feat: Add conversion script to allow opening logs in Chrome devtools
Ldoppea Nov 26, 2024
b5b72e4
feat: Improve conversion script to handle native measurements
Ldoppea Jan 9, 2025
cc424ce
feat: Patch rn-performance-flipper-reporter to handle custom categories
Ldoppea Nov 26, 2024
0ec0469
doc: Add documentation for debugging performances
Ldoppea Jan 16, 2025
1580870
feat: Add react-native-mmkv plugin
Ldoppea Nov 25, 2024
331afac
feat: Migrate storage from AsyncStorage to MMKV
Ldoppea Nov 25, 2024
99d3f55
feat: Add performance measurements on MMKV migration script
Ldoppea Dec 19, 2024
5fa33a8
feat: Migrate clientCacheStorage from AsyncStorage to MMKV
Ldoppea Dec 20, 2024
15d48b0
feat: Migrate Redux store from AsyncStorage to MMKV
Ldoppea Dec 4, 2024
d5fd842
feat: Migrate Offline's platform storage from AsyncStorage to MMKV
Ldoppea Dec 4, 2024
1db03a1
feat: Debounce PouchDB replication
Ldoppea Nov 26, 2024
9d93c8f
feat: Delay important files downloading 30s after startup
Ldoppea Nov 26, 2024
9833992
feat: Delay clients `synchronize()` call 10s after startup
Ldoppea Nov 27, 2024
b8a83d8
feat: Delay icon's caching manager 30s after startup
Ldoppea Dec 4, 2024
81a59f2
fix: Configure NetService reachabilityUrl earlier on app startup
Ldoppea Dec 4, 2024
bdeff9a
feat: Add cache for NetService state
Ldoppea Dec 4, 2024
be1f1d5
feat: Upgrade pouchdb-adapter-react-native-sqlite to v4
Ldoppea Nov 12, 2024
8d7f33b
fix: Enforce OpenSSL-Universal for iOS build
Ldoppea Nov 12, 2024
e2491c9
feat: Upgrade cozy-client and cozy-pouch-link to `52.0.0`
Ldoppea Dec 20, 2024
facc94b
fix: Enforce Stack queries when doing backup
Ldoppea Dec 20, 2024
86c3ec6
fix: Correctly handle removal of unimportant cached files
Ldoppea Dec 18, 2024
6f8281f
feat: Remove old hack for DefaultRedirectionUrl migration
Ldoppea Dec 20, 2024
a6a1507
feat: Add cozy-realtime package
Ldoppea Jan 12, 2025
9ba38d1
refactor: Move `triggerPouchReplication()` code into its own file
Ldoppea Jan 12, 2025
baeea04
feat: Trigger PouchDB replication when apps is restored from background
Ldoppea Jan 12, 2025
bd23c97
feat: Register CozyRealtime plugin into CozyClient
Ldoppea Jan 12, 2025
1f5a1eb
feat: Trigger PouchDB replication when realtime event is received
Ldoppea Jan 12, 2025
bf014c9
feat: Add cozy-dataproxy-lib package
Ldoppea Jan 12, 2025
bb81215
feat: Implement search feature
Ldoppea Jan 12, 2025
22d854e
fix: Wrap cozy-dataproxy-lib imports in a mockable file
Ldoppea Jan 16, 2025
60920bf
fix: Inject `{}` instead of `null` as second parameter of RealtimePlugin
Ldoppea Jan 20, 2025
9d8a055
feat: Upgrade cozy-dataproxy-lib to `3.2.0`
Ldoppea Feb 7, 2025
37d18a5
feat: Add performance measurement capabilities to SearchEngine
Ldoppea Jan 29, 2025
d1ebe71
feat: Add storage to SearchEngine constructor
Ldoppea Feb 7, 2025
cfaefec
chore: Upgrade cozy-client
paultranvan Feb 3, 2025
53702e3
feat: Bump required node version to 18
Ldoppea Jan 29, 2025
2d54141
fix: Cache `/public/prelogin` call to allow offline Unlock By Password
Ldoppea Feb 6, 2025
43279af
fix: Do not check password on server side when offline
Ldoppea Feb 6, 2025
78c2ed0
chore: Upgrade cozy-client
paultranvan Feb 3, 2025
e7f5199
fix: Do not log client instance
paultranvan Feb 6, 2025
4f64c48
feat: Add deviceName in perfs logs
paultranvan Feb 6, 2025
93f58d4
feat: Do not replicate io.cozy.jobs database
paultranvan Feb 6, 2025
08e7c1e
feat: Increase replication time
paultranvan Feb 6, 2025
499e034
feat: Upgrade cozy-dataproxy-lib to ``
Ldoppea Feb 11, 2025
9f3e214
feat: Upgrade cozy-realtime to `5.6.4`
Ldoppea Feb 11, 2025
a2dccba
feat: Upgrade cozy-client and cozy-pouch-link to `54.0.0`
Ldoppea Feb 11, 2025
758c2a8
feat: Speed up app display
paultranvan Feb 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16
18
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This notably includes the possiblity to run client-side konnectors, to get your
- [iOS only] Install XCode
- [Android only] Install Android Studio (or Android SDK)
- [Android only] Java 11
- [Android only] Install NDK (21.4.7075529) and CMake (3.10.2) from Android Studio's SDK Manager
- [Android only] Copy the Android's `debug.keystore` from Cozy's password-store into `android/app/debug.keystore`
- Run `pass show app-amirale/Certificates/debug.keystore > android/app/debug.keystore`
- If you don't have access to Cozy's password-store, just generate a new `debug.keystore` file
Expand Down
10 changes: 10 additions & 0 deletions __mocks__/react-native-performance-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import RNPerformance from 'react-native-performance'

export const mockRNPerformance: jest.Mocked<typeof RNPerformance> = {
mark: jest.fn(),
measure: jest.fn(),
default: {
mark: jest.fn(),
measure: jest.fn(),
}
} as unknown as jest.Mocked<typeof RNPerformance>
2 changes: 1 addition & 1 deletion __tests__/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const config = {
'<rootDir>/__tests__/transformer/imageTransformer.js'
},
transformIgnorePatterns: [
'node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|p-timeout?|p-wait-for?|@notifee?)|@fengweichong/react-native-gzip?/)'
'node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|p-timeout?|p-wait-for?|@notifee?)|@fengweichong/react-native-gzip|@craftzdog/*?/)'
],
rootDir: '../'
}
Expand Down
23 changes: 23 additions & 0 deletions __tests__/jestSetupFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { mockRNBackgroundGeolocation } from '../__mocks__/react-native-backgroun
import { mockRNFS } from '../__mocks__/react-native-fs-mock'
import { mockRNIAP } from '../__mocks__/react-native-iap-mock'
import { mockRNInAppBrowser } from '../__mocks__/react-native-inappbrowser-reborn-mock'
import { mockRNPerformance } from '../__mocks__/react-native-performance-mock'

jest.mock('react-native-device-info', () => mockRNDeviceInfo)

Expand All @@ -29,6 +30,7 @@ jest.mock('@sentry/react-native', () => ({
jest.mock('react-native-fs', () => mockRNFS)
jest.mock('react-native-iap', () => mockRNIAP)
jest.mock('react-native-inappbrowser-reborn', () => mockRNInAppBrowser)
jest.mock('react-native-performance', () => mockRNPerformance)
jest.mock('react-native-ios11-devicecheck', () => ({
getToken: jest.fn()
}))
Expand Down Expand Up @@ -127,3 +129,24 @@ jest.mock('../src/core/tools/env', () => ({
devlog: jest.fn(),
shouldDisableAutolock: jest.fn().mockReturnValue(false)
}))

jest.mock('../src/pouchdb/pouchdb', () => ({}))
jest.mock('react-native-quick-websql', () => ({}))

class mockPouchLink {
constructor() {}
}

jest.mock('cozy-pouch-link', () => {
return jest.fn().mockImplementation(() => {
return new mockPouchLink()
})
})

jest.mock('react-native-mail', () => ({
mail: jest.fn()
}))

jest.mock('/app/domain/search/dataproxy-wrapper', () => ({
SearchEngine: jest.fn()
}))
7 changes: 7 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ android {
prod {
}
}

packagingOptions {
pickFirst 'lib/x86/libcrypto.so'
pickFirst 'lib/x86_64/libcrypto.so'
pickFirst 'lib/armeabi-v7a/libcrypto.so'
pickFirst 'lib/arm64-v8a/libcrypto.so'
}
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,5 @@ public void onCreate() {

WebView.setWebContentsDebuggingEnabled(true);
OkHttpClientProvider.setOkHttpClientFactory(new UserAgentClientFactory());

try {
Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
field.setAccessible(true);
field.set(null, 50 * 1024 * 1024); // 50MB
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
}
4 changes: 3 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
buildscript {
ext {
buildToolsVersion = "34.0.0"
minSdkVersion = 21
minSdkVersion = 23
compileSdkVersion = 34
targetSdkVersion = 34
androidXBrowser = "1.4.0"
googlePlayServicesLocationVersion = "20.0.0"
DocumentScanner_compileSdkVersion = 34
DocumentScanner_targetSdkVersion = 34
QuickBase64_compileSdkVersion = 34
QuickBase64_targetSdkVersion = 34
ndkVersion = "25.1.8937393"
kotlinVersion = "1.8.0"
// To solve a conflict between flipper and react-native-background-geolocation
Expand Down
4 changes: 4 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ module.exports = {
root: ['./'],
alias: {
'^/(.+)': './src/\\1',
'pouchdb-collate': '@craftzdog/pouchdb-collate-react-native',
crypto: 'react-native-quick-crypto',
stream: 'readable-stream',
buffer: '@craftzdog/react-native-buffer',
'@cozy/minilog': 'cozy-minilog'
},
extensions: [
Expand Down
4 changes: 4 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ title: Cozy React Native documentation - Table of contents
- [How to install cozy-home in local assets](how-to-install-home.md)
- [How to retrieve logs in release mode](how-to-retrieve-logs-in-release.md)
- [How to debug cozy-bar in local](how-to-debug-cozy-bar.md)
- [How to debug notifications](how-to-debug-notifications.md)
- [How to debug Onboarding partner](how-to-debug-onboarding-partner.md)
- [How to debug Offline mode](how-to-debug-offline-mode.md)

## API documentations

- [FlagshipUI API](/src/app/view/FlagshipUI/README.md)
- [White Labels management](/white_label/README.md)
- [How to make cozy-apps offline compatible](/how-to-make-cozy-app-offline-compatible.md)
44 changes: 44 additions & 0 deletions docs/how-to-debug-offline-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# How to debug Offline mode

The Flagship app now handle Offline mode, this means that it can be open and run while the device is offline

This features implies that we can debug the app while using an offline device. This document explains how to do it

## Android emulator

On android, in order to set the device offline, use the top drawer menu, open the `Internet` menu and then disable both the Mobile Data and the Wi-Fi entries

Since ReactNative 0.72, the ReactNative debug link won't work by default if the emulator is offline. This can be fixing by running the following commands from a terminal while the emulator is running:
- `adb root`
- `adb reverse tcp:8081 tcp:8081`
- `adb shell setprop metro.host "localhost"`

When executed, those commands allow to build, deploy and hot-reload the ReactNative app from an offline emulator. The debug console is also functional

## iOS simulator

iOS simulator seems not to provide a comfortable way to debug the app offline. The only way to set the simulator offline is to set the entire computer offline, but this is not an acceptable solution is we are debuging using a locally running cozy-stack as it will still be reachable by the simulator

## Physical devices

On physical iOS and Android device, it is possible to debug the app by setting the device offline

However this will break build, hot-reload and console debugging features

To mitigate this, it is possible to use Universal Links to extract console logs and DB files from the device

For console logs, please refer to [How to retrieve logs in release mode](how-to-retrieve-logs-in-release.md) documentation

For DB files, it is possible to send them by email using the following link:

- https://links.mycozy.cloud/flagship/senddb or [cozy://senddb](cozy://senddb)
- trigger the OS send email intent pre-filled with DB files and Cozy's support email

## Reset local PouchDB

While debugging offline features, it is possible to corrupt the local PouchDB files (i.e. by injecting non valid documents)

It is possible to reset the local PouchDB files using the following link:

- https://links.mycozy.cloud/flagship/resetdb or [cozy://resetdb](cozy://resetdb)
- Reset the local PouchDB and restart the app
114 changes: 114 additions & 0 deletions docs/how-to-debug-performances.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# How to debug performances

Since [#1264](https://github.com/cozy/cozy-flagship-app/pull/1264) it is possible to measure the Flagship App's performances.

This document's goal is to describe how to retrieve measurements, how to read them and how to add new measurements.

The performance measurements are based on `react-native-performances` plugin and are complementary to CozyClient performance API implementation. More about those two concept can be read here:
- `react-native-performances`: https://github.com/oblador/react-native-performance
- CozyClient Performance API: https://github.com/cozy/cozy-client/blob/master/docs/performances.md

# Nomenclature

- `PerformanceAPI`: The API provided by CozyClient for measuring timings in the code base
- `Performance devtools`: Browsers devtools pane dedicated to performance (i.e. [Chrome devtools](https://developer.chrome.com/docs/devtools/performance) and [Firefox profiled](https://profiler.firefox.com/docs/#/))
- `Flipper performances plugin`: Plugin for Flipper dedicated to performance readings
- `Mark`: A temporal event
- `Measure`: A timing measurement between two temporal events

# Retrieve measurements

There are two way to retrieve measurements:

- In realtime using Flipper
- Asynchronously using Universal Links

## Flipper plugin

Flipper allows to read performance measurements in realtime through the `flipper-plugin-performance` plugin:

- Open Flipper
- Install the plugin `flipper-plugin-performance`
- Start the Flagship app in development mode
- On Flipper, open the `Performance` pane

![Screenshot of the Flipper plugin](./images/performances-flipper.png)

## Universal Links

When it is not possible to use the Flipper plugin, then the Flagship App allows to share performances measurements by email.

To do this:

- Open the Flagship app and do the scenario that needs to be measured
- Open one of the following links:
- https://links.mycozy.cloud/flagship/sendperfs
- cozy://sendperfs

When clicked, the Flagship App will upload the performance measurements for the current session in the user's Cozy and then an email intent will allow to send a link to download them.

The measurements are uploaded into the `Settings/AALogs/<current_date>` folder.

# Read the measurements

When downloading the measurements that were generated through Universal Link, then it is possible to read them using Chromium devtools.

To do this:

- Download the measurements file
- From the `cozy-flagship-app` project, run the following command:
- `yarn perf:convert <path_to_downloaded_file>`
- This will generate a new file in the same folder as the targeted file, and suffixed with `_converted`
- In a Chromium browser, open the devtools
- Open the `Performance` pane
- In the upper-left of the pane, click on `Load profile...` and selected the `_converted` file

![Screenshot of the Chromium devtools](./images/performances-devtools.png)

# Add new measurements

In order to add new measurements, it is possible to use the API from `/app/domain/performances/measure`.

This API provides `mark()` and `measure()` methods that are the core concept of doing measurements.

Those methods have the same behavior as the ones available in CozyClient. Their API and behaviour are described in [the related documentation](https://github.com/cozy/cozy-client/blob/master/docs/performances.md#mark-method)

## Add new measurements in a method

In order to measure the duration of a methods or part of a methods:

```js
import rnperformance from '/app/domain/performances/measure'

const someMethod = () => {
const markName = rnperformance.mark('someMethod')

// ... Method code

rnperformance.measure({ markName })
}
```


## Add new measurements in a React component

In order to measure the duration of a React component initialization:

```js
import rnperformance from '/app/domain/performances/measure'

const SomeReactComponent = () => {
const [markName] = useState(() => rnperformance.mark('SomeReactComponent'))

useEffect(() => {
rnperformance.measure({
markName: markName,
measureName: 'Mount <App />'
})
}, [markName])
}
```

## Add new measurements in CozyClient

See [related documentation](https://github.com/cozy/cozy-client/blob/master/docs/performances.md)
Loading
Loading