react-native-nitro-version-check 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NitroVersionCheck.podspec +31 -0
- package/README.md +117 -0
- package/android/CMakeLists.txt +29 -0
- package/android/build.gradle +142 -0
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/cpp-adapter.cpp +9 -0
- package/android/src/main/java/com/margelo/nitro/nitroversioncheck/HybridVersionCheck.kt +74 -0
- package/android/src/main/java/com/margelo/nitro/nitroversioncheck/NitroVersionCheckPackage.kt +18 -0
- package/ios/Bridge.h +8 -0
- package/ios/HybridVersionCheck.swift +71 -0
- package/lib/index.d.ts +168 -0
- package/lib/index.js +174 -0
- package/lib/semver.d.ts +22 -0
- package/lib/semver.js +51 -0
- package/lib/specs/Version.nitro.d.ts +14 -0
- package/lib/specs/Version.nitro.js +1 -0
- package/lib/types/UpdateResult.d.ts +6 -0
- package/lib/types/UpdateResult.js +1 -0
- package/nitro.json +18 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroVersionCheck+autolinking.cmake +81 -0
- package/nitrogen/generated/android/NitroVersionCheck+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroVersionCheckOnLoad.cpp +47 -0
- package/nitrogen/generated/android/NitroVersionCheckOnLoad.hpp +34 -0
- package/nitrogen/generated/android/c++/JHybridVersionCheckSpec.cpp +129 -0
- package/nitrogen/generated/android/c++/JHybridVersionCheckSpec.hpp +72 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroversioncheck/HybridVersionCheckSpec.kt +84 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroversioncheck/NitroVersionCheckOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NitroVersionCheck+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroVersionCheck-Swift-Cxx-Bridge.cpp +57 -0
- package/nitrogen/generated/ios/NitroVersionCheck-Swift-Cxx-Bridge.hpp +179 -0
- package/nitrogen/generated/ios/NitroVersionCheck-Swift-Cxx-Umbrella.hpp +46 -0
- package/nitrogen/generated/ios/NitroVersionCheckAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NitroVersionCheckAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridVersionCheckSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridVersionCheckSpecSwift.hpp +123 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridVersionCheckSpec.swift +61 -0
- package/nitrogen/generated/ios/swift/HybridVersionCheckSpec_cxx.swift +227 -0
- package/nitrogen/generated/shared/c++/HybridVersionCheckSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridVersionCheckSpec.hpp +70 -0
- package/package.json +116 -0
- package/react-native.config.js +16 -0
- package/src/index.ts +185 -0
- package/src/semver.ts +54 -0
- package/src/specs/Version.nitro.ts +16 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "NitroVersionCheck"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 }
|
|
14
|
+
s.source = { :git => "https://github.com/mrousavy/nitro.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = [
|
|
17
|
+
# Implementation (Swift)
|
|
18
|
+
"ios/**/*.{swift}",
|
|
19
|
+
# Autolinking/Registration (Objective-C++)
|
|
20
|
+
"ios/**/*.{m,mm}",
|
|
21
|
+
# Implementation (C++ objects)
|
|
22
|
+
"cpp/**/*.{hpp,cpp}",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
load 'nitrogen/generated/ios/NitroVersionCheck+autolinking.rb'
|
|
26
|
+
add_nitrogen_files(s)
|
|
27
|
+
|
|
28
|
+
s.dependency 'React-jsi'
|
|
29
|
+
s.dependency 'React-callinvoker'
|
|
30
|
+
install_modules_dependencies(s)
|
|
31
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
react-native-nitro-version-check
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<b>A fast, modern version-checking library for React Native, powered by <a href="https://github.com/mrousavy/nitro">Nitro Modules</a>.</b>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
A drop-in replacement for the unmaintained <a href="https://github.com/kimxogus/react-native-version-check"><code>react-native-version-check</code></a> â rewritten from scratch with <a href="https://github.com/mrousavy/nitro">Nitro Modules</a>.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<br />
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- ⥠**Synchronous access** to version, build number, package name, and country
|
|
18
|
+
- ðŠ **Store version lookup** from the App Store or Play Store
|
|
19
|
+
- ð **Granular update checks** â major, minor, or patch
|
|
20
|
+
- ðĶ **Install source detection** â TestFlight, App Store, Play Store, or sideloaded
|
|
21
|
+
- ðŠķ **Tiny footprint** â pure Swift on iOS, Kotlin on Android
|
|
22
|
+
|
|
23
|
+
## Performance
|
|
24
|
+
|
|
25
|
+
Benchmarked against [`react-native-version-check`](https://github.com/kimxogus/react-native-version-check). 100,000 iterations averaged over 5 runs on an iPhone 12:
|
|
26
|
+
|
|
27
|
+
| Method | Speedup |
|
|
28
|
+
|--------|---------|
|
|
29
|
+
| `getAllInfo` | **~3.1x faster** |
|
|
30
|
+
| `packageName` | **~1.6x faster** |
|
|
31
|
+
| `version` | **~1.6x faster** |
|
|
32
|
+
| `buildNumber` | **~1.6x faster** |
|
|
33
|
+
| `getCountry` | **~3.1x faster** |
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
bun add react-native-nitro-version-check react-native-nitro-modules
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For Expo projects, run prebuild:
|
|
42
|
+
```sh
|
|
43
|
+
npx expo prebuild
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
For bare React Native projects:
|
|
47
|
+
```sh
|
|
48
|
+
cd ios && pod install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { VersionCheck, getCountry, getStoreUrl, getLatestVersion, needsUpdate } from 'react-native-nitro-version-check'
|
|
55
|
+
|
|
56
|
+
// Sync properties
|
|
57
|
+
VersionCheck.version // "1.2.0"
|
|
58
|
+
VersionCheck.buildNumber // "42"
|
|
59
|
+
VersionCheck.packageName // "com.example.app"
|
|
60
|
+
VersionCheck.installSource // "appstore" | "testflight" | "playstore" | undefined
|
|
61
|
+
getCountry() // "US"
|
|
62
|
+
|
|
63
|
+
// Async
|
|
64
|
+
const url = await getStoreUrl() // App Store / Play Store URL
|
|
65
|
+
const latest = await getLatestVersion() // "1.3.0"
|
|
66
|
+
|
|
67
|
+
if (await needsUpdate()) {
|
|
68
|
+
Linking.openURL(await getStoreUrl())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Only prompt for major updates
|
|
72
|
+
if (await needsUpdate({ level: 'major' })) {
|
|
73
|
+
// 1.x â 2.x
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
### `VersionCheck`
|
|
80
|
+
|
|
81
|
+
| Property | Type | Description |
|
|
82
|
+
|----------|------|-------------|
|
|
83
|
+
| `version` | `string` | App version |
|
|
84
|
+
| `buildNumber` | `string` | Build number |
|
|
85
|
+
| `packageName` | `string` | Bundle ID / Application ID |
|
|
86
|
+
| `installSource` | `string \| undefined` | `"appstore"` `"testflight"` `"playstore"` or `undefined` |
|
|
87
|
+
| `getCountry()` | `string` | Device's 2-letter ISO country code |
|
|
88
|
+
| `getStoreUrl()` | `Promise<string>` | App Store / Play Store URL |
|
|
89
|
+
| `getLatestVersion()` | `Promise<string>` | Latest version in the store |
|
|
90
|
+
| `needsUpdate()` | `Promise<boolean>` | Whether an update is available |
|
|
91
|
+
|
|
92
|
+
### Standalone exports
|
|
93
|
+
|
|
94
|
+
Also available as individual named exports:
|
|
95
|
+
|
|
96
|
+
| Export | Returns | Description |
|
|
97
|
+
|--------|---------|-------------|
|
|
98
|
+
| `getCountry()` | `string` | Device's 2-letter ISO country code |
|
|
99
|
+
| `getStoreUrl()` | `Promise<string>` | App Store / Play Store URL |
|
|
100
|
+
| `getLatestVersion()` | `Promise<string>` | Latest version in the store |
|
|
101
|
+
| `needsUpdate(options?)` | `Promise<boolean>` | Whether an update is available |
|
|
102
|
+
|
|
103
|
+
#### `needsUpdate` options
|
|
104
|
+
|
|
105
|
+
| Option | Type | Default | Description |
|
|
106
|
+
|--------|------|---------|-------------|
|
|
107
|
+
| `level` | `"major" \| "minor" \| "patch"` | `"patch"` | Minimum version bump to trigger `true` |
|
|
108
|
+
|
|
109
|
+
### Utilities
|
|
110
|
+
|
|
111
|
+
| Function | Returns | Description |
|
|
112
|
+
|----------|---------|-------------|
|
|
113
|
+
| `compareVersions(v1, v2)` | `-1 \| 0 \| 1` | Compare two semver strings |
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
project(NitroVersionCheck)
|
|
2
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
3
|
+
|
|
4
|
+
set (PACKAGE_NAME NitroVersionCheck)
|
|
5
|
+
set (CMAKE_VERBOSE_MAKEFILE ON)
|
|
6
|
+
set (CMAKE_CXX_STANDARD 20)
|
|
7
|
+
|
|
8
|
+
# Define C++ library and add all sources
|
|
9
|
+
add_library(${PACKAGE_NAME} SHARED
|
|
10
|
+
src/main/cpp/cpp-adapter.cpp
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# Add Nitrogen specs :)
|
|
14
|
+
include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroVersionCheck+autolinking.cmake)
|
|
15
|
+
|
|
16
|
+
# Set up local includes
|
|
17
|
+
include_directories(
|
|
18
|
+
"src/main/cpp"
|
|
19
|
+
"../cpp"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
find_library(LOG_LIB log)
|
|
23
|
+
|
|
24
|
+
# Link all libraries together
|
|
25
|
+
target_link_libraries(
|
|
26
|
+
${PACKAGE_NAME}
|
|
27
|
+
${LOG_LIB}
|
|
28
|
+
android # <-- Android core
|
|
29
|
+
)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
repositories {
|
|
3
|
+
google()
|
|
4
|
+
mavenCentral()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath "com.android.tools.build:gradle:9.0.1"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def reactNativeArchitectures() {
|
|
13
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
14
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def isNewArchitectureEnabled() {
|
|
18
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply plugin: "com.android.library"
|
|
22
|
+
apply plugin: 'org.jetbrains.kotlin.android'
|
|
23
|
+
apply from: '../nitrogen/generated/android/NitroVersionCheck+autolinking.gradle'
|
|
24
|
+
apply from: "./fix-prefab.gradle"
|
|
25
|
+
|
|
26
|
+
if (isNewArchitectureEnabled()) {
|
|
27
|
+
apply plugin: "com.facebook.react"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def getExtOrDefault(name) {
|
|
31
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroVersionCheck_" + name]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def getExtOrIntegerDefault(name) {
|
|
35
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroVersionCheck_" + name]).toInteger()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
android {
|
|
39
|
+
namespace "com.margelo.nitro.nitroversioncheck"
|
|
40
|
+
|
|
41
|
+
ndkVersion getExtOrDefault("ndkVersion")
|
|
42
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
43
|
+
|
|
44
|
+
defaultConfig {
|
|
45
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
46
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
47
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
48
|
+
|
|
49
|
+
externalNativeBuild {
|
|
50
|
+
cmake {
|
|
51
|
+
cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
|
|
52
|
+
arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
|
53
|
+
abiFilters (*reactNativeArchitectures())
|
|
54
|
+
|
|
55
|
+
buildTypes {
|
|
56
|
+
debug {
|
|
57
|
+
cppFlags "-O1 -g"
|
|
58
|
+
}
|
|
59
|
+
release {
|
|
60
|
+
cppFlags "-O2"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
externalNativeBuild {
|
|
68
|
+
cmake {
|
|
69
|
+
path "CMakeLists.txt"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
packagingOptions {
|
|
74
|
+
excludes = [
|
|
75
|
+
"META-INF",
|
|
76
|
+
"META-INF/**",
|
|
77
|
+
"**/libc++_shared.so",
|
|
78
|
+
"**/libNitroModules.so",
|
|
79
|
+
"**/libfbjni.so",
|
|
80
|
+
"**/libjsi.so",
|
|
81
|
+
"**/libfolly_json.so",
|
|
82
|
+
"**/libfolly_runtime.so",
|
|
83
|
+
"**/libglog.so",
|
|
84
|
+
"**/libhermes.so",
|
|
85
|
+
"**/libhermes-executor-debug.so",
|
|
86
|
+
"**/libhermes_executor.so",
|
|
87
|
+
"**/libreactnative.so",
|
|
88
|
+
"**/libreactnativejni.so",
|
|
89
|
+
"**/libturbomodulejsijni.so",
|
|
90
|
+
"**/libreact_nativemodule_core.so",
|
|
91
|
+
"**/libjscexecutor.so"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
buildFeatures {
|
|
96
|
+
buildConfig true
|
|
97
|
+
prefab true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
buildTypes {
|
|
101
|
+
release {
|
|
102
|
+
minifyEnabled false
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
lintOptions {
|
|
107
|
+
disable "GradleCompatible"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
compileOptions {
|
|
111
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
112
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
sourceSets {
|
|
116
|
+
main {
|
|
117
|
+
if (isNewArchitectureEnabled()) {
|
|
118
|
+
java.srcDirs += [
|
|
119
|
+
// React Codegen files
|
|
120
|
+
"${project.buildDir}/generated/source/codegen/java"
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
repositories {
|
|
128
|
+
mavenCentral()
|
|
129
|
+
google()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
dependencies {
|
|
134
|
+
// For < 0.71, this will be from the local maven repo
|
|
135
|
+
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
136
|
+
//noinspection GradleDynamicVersion
|
|
137
|
+
implementation "com.facebook.react:react-native:+"
|
|
138
|
+
|
|
139
|
+
// Add a dependency on NitroModules
|
|
140
|
+
implementation project(":react-native-nitro-modules")
|
|
141
|
+
}
|
|
142
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
tasks.configureEach { task ->
|
|
2
|
+
// Make sure that we generate our prefab publication file only after having built the native library
|
|
3
|
+
// so that not a header publication file, but a full configuration publication will be generated, which
|
|
4
|
+
// will include the .so file
|
|
5
|
+
|
|
6
|
+
def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/
|
|
7
|
+
def matcher = task.name =~ prefabConfigurePattern
|
|
8
|
+
if (matcher.matches()) {
|
|
9
|
+
def variantName = matcher[0][1]
|
|
10
|
+
task.outputs.upToDateWhen { false }
|
|
11
|
+
task.dependsOn("externalNativeBuild${variantName}")
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
afterEvaluate {
|
|
16
|
+
def abis = reactNativeArchitectures()
|
|
17
|
+
rootProject.allprojects.each { proj ->
|
|
18
|
+
if (proj === rootProject) return
|
|
19
|
+
|
|
20
|
+
def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config ->
|
|
21
|
+
config.dependencies.any { dep ->
|
|
22
|
+
dep.group == project.group && dep.name == project.name
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!dependsOnThisLib && proj != project) return
|
|
26
|
+
|
|
27
|
+
if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants
|
|
32
|
+
// Touch the prefab_config.json files to ensure that in ExternalNativeJsonGenerator.kt we will re-trigger the prefab CLI to
|
|
33
|
+
// generate a libnameConfig.cmake file that will contain our native library (.so).
|
|
34
|
+
// See this condition: https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/ExternalNativeJsonGenerator.kt;l=207-219?q=createPrefabBuildSystemGlue
|
|
35
|
+
variants.all { variant ->
|
|
36
|
+
def variantName = variant.name
|
|
37
|
+
abis.each { abi ->
|
|
38
|
+
def searchDir = new File(proj.projectDir, ".cxx/${variantName}")
|
|
39
|
+
if (!searchDir.exists()) return
|
|
40
|
+
def matches = []
|
|
41
|
+
searchDir.eachDir { randomDir ->
|
|
42
|
+
def prefabFile = new File(randomDir, "${abi}/prefab_config.json")
|
|
43
|
+
if (prefabFile.exists()) matches << prefabFile
|
|
44
|
+
}
|
|
45
|
+
matches.each { prefabConfig ->
|
|
46
|
+
prefabConfig.setLastModified(System.currentTimeMillis())
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package com.margelo.nitro.nitroversioncheck
|
|
2
|
+
|
|
3
|
+
import com.margelo.nitro.NitroModules
|
|
4
|
+
import com.margelo.nitro.core.Promise
|
|
5
|
+
import java.net.HttpURLConnection
|
|
6
|
+
import java.net.URL
|
|
7
|
+
|
|
8
|
+
class HybridVersionCheck : HybridVersionCheckSpec() {
|
|
9
|
+
companion object {
|
|
10
|
+
private const val TIMEOUT_MS = 15_000
|
|
11
|
+
private val context = NitroModules.applicationContext
|
|
12
|
+
private val packageInfo = context?.packageManager?.getPackageInfo(context.packageName, 0)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public override val version = packageInfo?.versionName ?: "unknown"
|
|
16
|
+
|
|
17
|
+
public override val buildNumber = if (android.os.Build.VERSION.SDK_INT >= 28) {
|
|
18
|
+
if (packageInfo?.longVersionCode != null) packageInfo.longVersionCode.toString() else "unknown"
|
|
19
|
+
} else {
|
|
20
|
+
@Suppress("DEPRECATION")
|
|
21
|
+
if (packageInfo?.versionCode != null) packageInfo.versionCode.toString() else "unknown"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public override val packageName = packageInfo?.packageName ?: "unknown"
|
|
25
|
+
public override val installSource: String? = run {
|
|
26
|
+
val installer = if (android.os.Build.VERSION.SDK_INT >= 30) {
|
|
27
|
+
context?.packageManager?.getInstallSourceInfo(context.packageName)?.installingPackageName
|
|
28
|
+
} else {
|
|
29
|
+
@Suppress("DEPRECATION")
|
|
30
|
+
context?.packageManager?.getInstallerPackageName(context.packageName)
|
|
31
|
+
}
|
|
32
|
+
if (installer != null) "playstore" else null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override fun getCountry(): String {
|
|
36
|
+
return java.util.Locale.getDefault().country ?: "unknown"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun getStoreUrl(): Promise<String> {
|
|
40
|
+
return Promise.async {
|
|
41
|
+
"https://play.google.com/store/apps/details?id=$packageName"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun getLatestVersion(): Promise<String> {
|
|
46
|
+
return Promise.async {
|
|
47
|
+
try {
|
|
48
|
+
val url = URL("https://play.google.com/store/apps/details?id=$packageName&hl=en")
|
|
49
|
+
val connection = url.openConnection() as HttpURLConnection
|
|
50
|
+
connection.connectTimeout = TIMEOUT_MS
|
|
51
|
+
connection.readTimeout = TIMEOUT_MS
|
|
52
|
+
connection.setRequestProperty("User-Agent", "Mozilla/5.0")
|
|
53
|
+
val html = connection.inputStream.bufferedReader().use { it.readText() }
|
|
54
|
+
val regex = Regex("""\]\]\],\s*"(\d+\.\d+[\d.]*\d)"""")
|
|
55
|
+
val match = regex.find(html)
|
|
56
|
+
match?.groupValues?.get(1)
|
|
57
|
+
?: throw Exception("Could not parse latest version from Play Store page")
|
|
58
|
+
} catch (e: Exception) {
|
|
59
|
+
throw Exception("Failed to fetch latest version: ${e.message}", e)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun needsUpdate(): Promise<Boolean> {
|
|
65
|
+
return Promise.async {
|
|
66
|
+
try {
|
|
67
|
+
val latest = getLatestVersion().await()
|
|
68
|
+
version != latest
|
|
69
|
+
} catch (e: Exception) {
|
|
70
|
+
throw Exception("Failed to check for updates: ${e.message}", e)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package com.margelo.nitro.nitroversioncheck
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.NativeModule
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
6
|
+
import com.facebook.react.BaseReactPackage
|
|
7
|
+
|
|
8
|
+
class NitroVersionCheckPackage : BaseReactPackage() {
|
|
9
|
+
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
|
|
10
|
+
|
|
11
|
+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { HashMap() }
|
|
12
|
+
|
|
13
|
+
companion object {
|
|
14
|
+
init {
|
|
15
|
+
NitroVersionCheckOnLoad.initializeNative()
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
package/ios/Bridge.h
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import NitroModules
|
|
3
|
+
|
|
4
|
+
class HybridVersionCheck: HybridVersionCheckSpec {
|
|
5
|
+
private static let session: URLSession = {
|
|
6
|
+
let config = URLSessionConfiguration.default
|
|
7
|
+
config.timeoutIntervalForRequest = 15
|
|
8
|
+
config.timeoutIntervalForResource = 30
|
|
9
|
+
return URLSession(configuration: config)
|
|
10
|
+
}()
|
|
11
|
+
|
|
12
|
+
var version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "unknown"
|
|
13
|
+
var buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "unknown"
|
|
14
|
+
var packageName = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String ?? "unknown"
|
|
15
|
+
var installSource: String? = {
|
|
16
|
+
guard let receiptURL = Bundle.main.appStoreReceiptURL,
|
|
17
|
+
FileManager.default.fileExists(atPath: receiptURL.path) else {
|
|
18
|
+
return nil
|
|
19
|
+
}
|
|
20
|
+
if receiptURL.lastPathComponent == "sandboxReceipt" {
|
|
21
|
+
return "testflight"
|
|
22
|
+
}
|
|
23
|
+
return "appstore"
|
|
24
|
+
}()
|
|
25
|
+
|
|
26
|
+
func getCountry() throws -> String {
|
|
27
|
+
if #available(iOS 16, *) {
|
|
28
|
+
return Locale.current.region?.identifier ?? "unknown"
|
|
29
|
+
}
|
|
30
|
+
return Locale.current.regionCode ?? "unknown"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func getStoreUrl() throws -> Promise<String> {
|
|
34
|
+
return Promise.async {
|
|
35
|
+
let bundleId = Bundle.main.bundleIdentifier ?? ""
|
|
36
|
+
let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
|
|
37
|
+
let (data, _) = try await HybridVersionCheck.session.data(from: url)
|
|
38
|
+
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
39
|
+
let results = json["results"] as? [[String: Any]],
|
|
40
|
+
let trackViewUrl = results.first?["trackViewUrl"] as? String else {
|
|
41
|
+
throw NSError(domain: "VersionCheck", code: 1, userInfo: [NSLocalizedDescriptionKey: "App not found on App Store"])
|
|
42
|
+
}
|
|
43
|
+
return trackViewUrl
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func getLatestVersion() throws -> Promise<String> {
|
|
48
|
+
return Promise.async {
|
|
49
|
+
let bundleId = Bundle.main.bundleIdentifier ?? ""
|
|
50
|
+
let url = URL(string: "https://itunes.apple.com/lookup?bundleId=\(bundleId)")!
|
|
51
|
+
let (data, _) = try await HybridVersionCheck.session.data(from: url)
|
|
52
|
+
guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
53
|
+
let results = json["results"] as? [[String: Any]],
|
|
54
|
+
let latestVersion = results.first?["version"] as? String else {
|
|
55
|
+
throw NSError(domain: "VersionCheck", code: 2, userInfo: [NSLocalizedDescriptionKey: "App not found on App Store"])
|
|
56
|
+
}
|
|
57
|
+
return latestVersion
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func needsUpdate() throws -> Promise<Bool> {
|
|
62
|
+
return Promise.async { [self] in
|
|
63
|
+
do {
|
|
64
|
+
let latest = try await self.getLatestVersion().await()
|
|
65
|
+
return self.version != latest
|
|
66
|
+
} catch {
|
|
67
|
+
throw NSError(domain: "VersionCheck", code: 3, userInfo: [NSLocalizedDescriptionKey: "Failed to check for updates: \(error.localizedDescription)"])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|