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

feat: react-native with web support #126

Merged
merged 50 commits into from
Jul 15, 2022
Merged

feat: react-native with web support #126

merged 50 commits into from
Jul 15, 2022

Conversation

bgiori
Copy link
Collaborator

@bgiori bgiori commented Jun 28, 2022

Summary

Add analytics-react-native package, published as @amplitude/analytics-react-native

  • Supports react-native web & expo
  • Complete feature parity with analytics-browser for react-native/expo web
    • Cookie support, attribution tracking etc.
  • Mobile platforms (android & ios) utilize native app context modules for accessing system info, async storage for persistence.

Diff between packages/analytics-browser/src and packages/analytics-react-native/src

diff -r packages/analytics-browser/src packages/analytics-react-native/src -x version.ts

Output:

Only in packages/analytics-browser/src: browser-client.ts
diff -r -x version.ts packages/analytics-browser/src/config.ts packages/analytics-react-native/src/config.ts
3,4c3,4
<   BrowserOptions,
<   BrowserConfig as IBrowserConfig,
---
>   ReactNativeOptions,
>   ReactNativeConfig as IReactNativeConfig,
53c53
< export class BrowserConfig extends Config implements IBrowserConfig {
---
> export class ReactNativeConfig extends Config implements IReactNativeConfig {
66c66
<   constructor(apiKey: string, userId?: string, options?: BrowserOptions) {
---
>   constructor(apiKey: string, userId?: string, options?: ReactNativeOptions) {
134c134
< export const useBrowserConfig = async (
---
> export const useReactNativeConfig = async (
137,138c137,138
<   options?: BrowserOptions,
< ): Promise<IBrowserConfig> => {
---
>   options?: ReactNativeOptions,
> ): Promise<IReactNativeConfig> => {
147c147
<   return new BrowserConfig(apiKey, userId ?? cookies?.userId, {
---
>   return new ReactNativeConfig(apiKey, userId ?? cookies?.userId, {
162c162
<   overrides?: BrowserOptions,
---
>   overrides?: ReactNativeOptions,
173c173
< export const createFlexibleStorage = async <T>(options: BrowserOptions): Promise<Storage<T>> => {
---
> export const createFlexibleStorage = async <T>(options: ReactNativeOptions): Promise<Storage<T>> => {
189c189
< export const createEventsStorage = async (overrides?: BrowserOptions): Promise<Storage<Event[]>> => {
---
> export const createEventsStorage = async (overrides?: ReactNativeOptions): Promise<Storage<Event[]>> => {
Only in packages/analytics-react-native/src: constants.ts
diff -r -x version.ts packages/analytics-browser/src/index.ts packages/analytics-react-native/src/index.ts
20c20
< } from './browser-client';
---
> } from './react-native-client';
23c23,24
< export * as Types from '@amplitude/analytics-types';
---
> import * as Types from '@amplitude/analytics-types';
> export { Types };
diff -r -x version.ts packages/analytics-browser/src/plugins/context.ts packages/analytics-react-native/src/plugins/context.ts
1c1
< import { BeforePlugin, BrowserConfig, Event, PluginType } from '@amplitude/analytics-types';
---
> import { BeforePlugin, ReactNativeConfig, Event, PluginType } from '@amplitude/analytics-types';
5a6
> import { NativeModules } from 'react-native';
9a11,26
> type NativeContext = {
>   version: string;
>   platform: string;
>   language: string;
>   os_name: string;
>   os_version: string;
>   device_brand: string;
>   device_manufacturer: string;
>   device_model: string;
>   carrier: string;
> };
> 
> export interface AmplitudeReactNative {
>   getApplicationContext(): Promise<NativeContext>;
> }
> 
17c34
<   config: BrowserConfig;
---
>   config: ReactNativeConfig;
20c37,40
<   library = `amplitude-ts/${VERSION}`;
---
>   nativeModule: AmplitudeReactNative | undefined = NativeModules.AmplitudeReactNative as
>     | AmplitudeReactNative
>     | undefined;
>   library = `amplitude-react-native-ts/${VERSION}`;
31c51
<   setup(config: BrowserConfig): Promise<undefined> {
---
>   setup(config: ReactNativeConfig): Promise<undefined> {
33d52
< 
48,51c67,75
<     const osName = this.uaResult.browser.name;
<     const osVersion = this.uaResult.browser.version;
<     const deviceModel = this.uaResult.device.model || this.uaResult.os.name;
<     const deviceVendor = this.uaResult.device.vendor;
---
>     const nativeContext = await this.nativeModule?.getApplicationContext();
>     const appVersion = nativeContext?.version || this.config.appVersion;
>     const platform = nativeContext?.platform || BROWSER_PLATFORM;
>     const osName = nativeContext?.os_name || this.uaResult.browser.name;
>     const osVersion = nativeContext?.os_version || this.uaResult.browser.version;
>     const deviceVendor = nativeContext?.device_manufacturer || this.uaResult.device.vendor;
>     const deviceModel = nativeContext?.device_model || this.uaResult.device.model || this.uaResult.os.name;
>     const language = nativeContext?.language || getLanguage();
>     const carrier = nativeContext?.carrier;
58,59c82,83
<       ...(this.config.appVersion && { app_version: this.config.appVersion }),
<       ...(this.config.trackingOptions.platform && { platform: BROWSER_PLATFORM }),
---
>       ...(this.config.appVersion && { app_version: appVersion }),
>       ...(this.config.trackingOptions.platform && { platform: platform }),
64c88,89
<       ...(this.config.trackingOptions.language && { language: getLanguage() }),
---
>       ...(this.config.trackingOptions.language && { language: language }),
>       ...(this.config.trackingOptions.carrier && { carrier: carrier }),
Only in packages/analytics-react-native/src: react-native-client.ts
Only in packages/analytics-browser/src: snippet-index.ts
diff -r -x version.ts packages/analytics-browser/src/storage/cookie.ts packages/analytics-react-native/src/storage/cookie.ts
1a2
> import { isNative } from '../utils/platform';
10a12,14
>     if (isNative()) {
>       return false;
>     }
diff -r -x version.ts packages/analytics-browser/src/storage/local-storage.ts packages/analytics-react-native/src/storage/local-storage.ts
1a2
> import AsyncStorage from '@react-native-async-storage/async-storage';
40c41
<     return window.localStorage.getItem(key) || undefined;
---
>     return (await AsyncStorage.getItem(key)) || undefined;
45c46
<       window.localStorage.setItem(key, JSON.stringify(value));
---
>       await AsyncStorage.setItem(key, JSON.stringify(value));
53c54
<       window.localStorage.removeItem(key);
---
>       await AsyncStorage.removeItem(key);
61c62
<       window.localStorage.clear();
---
>       await AsyncStorage.clear();
Only in packages/analytics-react-native/src/utils: platform.ts
diff -r -x version.ts packages/analytics-browser/src/utils/query-params.ts packages/analytics-react-native/src/utils/query-params.ts
0a1,2
> import { isNative } from './platform';
> 
1a4,6
>   if (isNative()) {
>     return {};
>   }

Diff between packages/analytics-browser/src/browser-client.ts and packages/analytics-react-native/src/react-native-client.ts

diff packages/analytics-browser/src/browser-client.ts packages/analytics-react-native/src/react-native-client.ts

Output:

3,6c3
<   AdditionalBrowserOptions,
<   AttributionBrowserOptions,
<   BrowserConfig,
<   BrowserOptions,
---
>   ReactNativeConfig,
12a10,12
>   ReactNativeOptions,
>   AdditionalReactNativeOptions,
>   AttributionReactNativeOptions,
16c16
< import { useBrowserConfig, createTransport, createDeviceId, createFlexibleStorage } from './config';
---
> import { useReactNativeConfig, createTransport, createDeviceId, createFlexibleStorage } from './config';
18a19
> import { isNative } from './utils/platform';
20,21c21,22
< export class AmplitudeBrowser extends AmplitudeCore<BrowserConfig> {
<   async init(apiKey: string, userId?: string, options?: BrowserOptions & AdditionalBrowserOptions) {
---
> export class AmplitudeReactNative extends AmplitudeCore<ReactNativeConfig> {
>   async init(apiKey: string, userId?: string, options?: ReactNativeOptions & AdditionalReactNativeOptions) {
25,26c26,27
<     // Step 2: Create browser config
<     const browserOptions = await useBrowserConfig(apiKey, userId || oldCookies.userId, {
---
>     // Step 2: Create react native config
>     const reactNativeOptions = await useReactNativeConfig(apiKey, userId || oldCookies.userId, {
33c34
<     await super.init(undefined, undefined, browserOptions);
---
>     await super.init(undefined, undefined, reactNativeOptions);
57c58,61
<   async runAttributionStrategy(attributionConfig?: AttributionBrowserOptions, isNewSession = false) {
---
>   async runAttributionStrategy(attributionConfig?: AttributionReactNativeOptions, isNewSession = false) {
>     if (isNative()) {
>       return;
>     }
142c146
< const client = new AmplitudeBrowser();
---
> const client = new AmplitudeReactNative();

Suggested Follow-up Modularization

Since so much code is shared, we should really re-modularize browser and react-native packages into an analytics-client-common package to avoid maintaining two extremely similar source sets.

Also, android native code is copied and shared from Ampliutude-Kotlin. Need to to merge and publish amplitude/Amplitude-Kotlin#39 then pull in the dependency.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: NO

Base automatically changed from async-storage-interface to main June 28, 2022 21:45
@bgiori bgiori changed the title React native feat: react-native with web support Jun 28, 2022
@bgiori bgiori marked this pull request as ready for review July 13, 2022 01:41
Copy link
Collaborator

@kevinpagtakhan kevinpagtakhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome!!! mostly asking questions here, and suggesting other code may be omitted

packages/analytics-browser/README.md Outdated Show resolved Hide resolved
packages/analytics-react-native/jest.config.js Outdated Show resolved Hide resolved
packages/analytics-react-native/jest.config.js Outdated Show resolved Hide resolved
packages/analytics-react-native/package.json Show resolved Hide resolved
packages/analytics-react-native/package.json Show resolved Hide resolved
packages/analytics-react-native/src/utils/query-params.ts Outdated Show resolved Hide resolved
packages/analytics-react-native/src/react-native-client.ts Outdated Show resolved Hide resolved
Copy link
Collaborator

@kevinpagtakhan kevinpagtakhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exciting!

@bgiori bgiori merged commit 5384130 into main Jul 15, 2022
@bgiori bgiori deleted the react-native branch July 15, 2022 20:21
curiousYi pushed a commit to curiousYi/Amplitude-TypeScript that referenced this pull request Jan 26, 2023
* Addng Infobip docs

* Fixing svg viewbox

* language tweaks

* fixing broken codesamples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants