From c362b8c5fc53c234353b7cc439650cd6a3a7f83a Mon Sep 17 00:00:00 2001 From: duguyihou Date: Sun, 25 Feb 2024 17:19:25 +1100 Subject: [PATCH] 5 update type for android (#9) * build: install ktor * build: install app-update-ktx * feat: implement getVersionInfo and startUpdate * revert: ktor * refactor: folder structure --- android/build.gradle | 5 +- .../java/com/neoversion/NeoVersionModule.kt | 51 +++++++++++++++++-- example/android/app/build.gradle | 1 + example/src/App.tsx | 3 +- src/Android/neoVersion.android.ts | 18 +++++++ src/Android/useNeoVersionCheck.android.ts | 33 ++++++++++++ src/{ => iOS}/alertButton.ts | 6 ++- src/{neoVersion.ts => iOS/neoVersion.ios.ts} | 2 +- src/{ => iOS}/rules.ts | 2 +- .../useNeoVersionCheck.ios.ts} | 11 +--- src/index.android.ts | 1 + src/index.ios.ts | 1 + src/index.tsx | 1 - src/types.ts | 7 +++ 14 files changed, 122 insertions(+), 20 deletions(-) create mode 100644 src/Android/neoVersion.android.ts create mode 100644 src/Android/useNeoVersionCheck.android.ts rename src/{ => iOS}/alertButton.ts (86%) rename src/{neoVersion.ts => iOS/neoVersion.ios.ts} (93%) rename src/{ => iOS}/rules.ts (94%) rename src/{useNeoVersionCheck.ts => iOS/useNeoVersionCheck.ios.ts} (87%) create mode 100644 src/index.android.ts create mode 100644 src/index.ios.ts delete mode 100644 src/index.tsx diff --git a/android/build.gradle b/android/build.gradle index b42dff4..478682c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,7 +1,9 @@ buildscript { // Buildscript is evaluated before everything else so we can't use getExtOrDefault def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["NeoVersion_kotlinVersion"] - + ext { + app_update_ktx = "2.1.0" + } repositories { google() mavenCentral() @@ -90,5 +92,6 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation("com.google.android.play:app-update-ktx:$app_update_ktx") } diff --git a/android/src/main/java/com/neoversion/NeoVersionModule.kt b/android/src/main/java/com/neoversion/NeoVersionModule.kt index 08c137e..5e7f086 100644 --- a/android/src/main/java/com/neoversion/NeoVersionModule.kt +++ b/android/src/main/java/com/neoversion/NeoVersionModule.kt @@ -1,9 +1,13 @@ package com.neoversion +import android.content.IntentSender.SendIntentException +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod -import com.facebook.react.bridge.Promise +import com.google.android.play.core.appupdate.AppUpdateManagerFactory +import com.google.android.play.core.install.model.UpdateAvailability class NeoVersionModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { @@ -12,14 +16,51 @@ class NeoVersionModule(reactContext: ReactApplicationContext) : return NAME } - // Example method - // See https://reactnative.dev/docs/native-modules-android + private val appUpdateManager = AppUpdateManagerFactory.create(reactContext) + + @ReactMethod + fun getVersionInfo(promise: Promise) { + val appUpdateInfoTask = appUpdateManager.appUpdateInfo + appUpdateInfoTask.addOnFailureListener { err -> + promise.reject("ERROR", err.toString()) + } + appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> + val map = Arguments.createMap() + val updateAvailability = appUpdateInfo.updateAvailability() + val isUpdateAvailable = updateAvailability == UpdateAvailability.UPDATE_AVAILABLE + map.putBoolean("isUpdateAvailable", isUpdateAvailable) + appUpdateInfo.clientVersionStalenessDays()?.let { + map.putInt("stalenessDays", it) + } + promise.resolve(map) + } + } + @ReactMethod - fun multiply(a: Double, b: Double, promise: Promise) { - promise.resolve(a * b) + fun startUpdate(updateType: Int = 0, promise: Promise) { + val appUpdateInfoTask = appUpdateManager.appUpdateInfo + appUpdateInfoTask.addOnFailureListener { err: Exception -> + promise.reject("ERROR", err.toString()) + } + appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> + try { + currentActivity?.let { + appUpdateManager.startUpdateFlowForResult( + appUpdateInfo, + updateType, + it, + IN_APP_UPDATE_REQUEST_CODE + ) + } + promise.resolve("DONE") + } catch (err: SendIntentException) { + promise.reject("ERROR", err.toString()) + } + } } companion object { const val NAME = "NeoVersion" + const val IN_APP_UPDATE_REQUEST_CODE = 42139 } } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d0c094c..07038eb 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -77,6 +77,7 @@ android { namespace "com.neoversionexample" defaultConfig { applicationId "com.neoversionexample" + // applicationId "com.facebook.katana" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 diff --git a/example/src/App.tsx b/example/src/App.tsx index 49fcbbb..13e72ba 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; import { StyleSheet, View, Text } from 'react-native'; -import { useNeoVersionCheck } from '../../src'; +import { useNeoVersionCheck } from '../../src/index.android'; export default function App() { useNeoVersionCheck(); + return ( React Native Neo Version diff --git a/src/Android/neoVersion.android.ts b/src/Android/neoVersion.android.ts new file mode 100644 index 0000000..93667d3 --- /dev/null +++ b/src/Android/neoVersion.android.ts @@ -0,0 +1,18 @@ +import { NativeModules } from 'react-native'; + +const neoVersion = NativeModules.NeoVersion; + +type VersionInfo = { + isUpdateAvailable: boolean; + stalenessDays: number; +}; + +export function getVersionInfo(): Promise> { + return neoVersion.getVersionInfo(); +} + +export function startUpdate(): Promise { + return neoVersion.startUpdate(); +} + +export default neoVersion; diff --git a/src/Android/useNeoVersionCheck.android.ts b/src/Android/useNeoVersionCheck.android.ts new file mode 100644 index 0000000..9e1077a --- /dev/null +++ b/src/Android/useNeoVersionCheck.android.ts @@ -0,0 +1,33 @@ +import { useEffect } from 'react'; +import { getVersionInfo, startUpdate } from './neoVersion.android'; +import { Alert } from 'react-native'; +import type { Configuration } from '../types'; + +export const useNeoVersionCheck = (configuration?: Partial) => { + useEffect(() => { + const performVersionCheck = async () => { + const info = await getVersionInfo(); + if (info.isUpdateAvailable) { + Alert.alert( + configuration?.title ?? 'Update Available', + configuration?.message ?? + 'Please update the app to have the best experience', + [ + { + text: 'Update', + onPress: () => { + startUpdate(); + }, + style: 'default', + }, + { + text: 'Next time', + style: 'default', + }, + ] + ); + } + }; + performVersionCheck(); + }, [configuration?.message, configuration?.title]); +}; diff --git a/src/alertButton.ts b/src/iOS/alertButton.ts similarity index 86% rename from src/alertButton.ts rename to src/iOS/alertButton.ts index 3b68de8..61de3c3 100644 --- a/src/alertButton.ts +++ b/src/iOS/alertButton.ts @@ -1,5 +1,9 @@ import type { AlertButton } from 'react-native'; -import { launchAppStore, presentNextTime, skipThisVersion } from './neoVersion'; +import { + launchAppStore, + presentNextTime, + skipThisVersion, +} from './neoVersion.ios'; export const updateButton = (): AlertButton => { return { diff --git a/src/neoVersion.ts b/src/iOS/neoVersion.ios.ts similarity index 93% rename from src/neoVersion.ts rename to src/iOS/neoVersion.ios.ts index 8f1ee26..9e45509 100644 --- a/src/neoVersion.ts +++ b/src/iOS/neoVersion.ios.ts @@ -1,5 +1,5 @@ import { NativeModules } from 'react-native'; -import type { UpdateType } from './types'; +import type { UpdateType } from '../types'; const neoVersion = NativeModules.NeoVersion; diff --git a/src/rules.ts b/src/iOS/rules.ts similarity index 94% rename from src/rules.ts rename to src/iOS/rules.ts index cd9d098..2f312a2 100644 --- a/src/rules.ts +++ b/src/iOS/rules.ts @@ -1,6 +1,6 @@ import type { AlertButton } from 'react-native'; import { nextTimeButton, skipButton, updateButton } from './alertButton'; -import { type AlertType, type UpdateType, type Rules } from './types'; +import { type AlertType, type UpdateType, type Rules } from '../types'; const criticalRules: Rules = { alertType: 'force', diff --git a/src/useNeoVersionCheck.ts b/src/iOS/useNeoVersionCheck.ios.ts similarity index 87% rename from src/useNeoVersionCheck.ts rename to src/iOS/useNeoVersionCheck.ios.ts index ff2b733..634a904 100644 --- a/src/useNeoVersionCheck.ts +++ b/src/iOS/useNeoVersionCheck.ios.ts @@ -1,15 +1,8 @@ import { useEffect } from 'react'; import { Alert } from 'react-native'; -import type { AlertType } from './types'; +import type { Configuration } from '../types'; import { generateAlertButtons, parse, shouldPresentAlert } from './rules'; -import { computeDaysSincePresentation, getVersionInfo } from './neoVersion'; - -type Configuration = { - title: string; - message: string; - alertType: AlertType; - frequency: number; -}; +import { computeDaysSincePresentation, getVersionInfo } from './neoVersion.ios'; export const useNeoVersionCheck = (configuration?: Partial) => { useEffect(() => { diff --git a/src/index.android.ts b/src/index.android.ts new file mode 100644 index 0000000..c6d5d62 --- /dev/null +++ b/src/index.android.ts @@ -0,0 +1 @@ +export { useNeoVersionCheck } from './Android/useNeoVersionCheck.android'; diff --git a/src/index.ios.ts b/src/index.ios.ts new file mode 100644 index 0000000..4865cc4 --- /dev/null +++ b/src/index.ios.ts @@ -0,0 +1 @@ +export { useNeoVersionCheck } from './iOS/useNeoVersionCheck.ios'; diff --git a/src/index.tsx b/src/index.tsx deleted file mode 100644 index aaab209..0000000 --- a/src/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { useNeoVersionCheck } from './useNeoVersionCheck'; diff --git a/src/types.ts b/src/types.ts index 5430583..1bbcdb3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -13,3 +13,10 @@ export type Rules = { alertType: AlertType; frequency: FrequencyVal | number; }; + +export type Configuration = { + title: string; + message: string; + alertType: AlertType; + frequency: number; +};