@acertijosapps/react-native-in-app-store-review 1.1.0
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/CHANGELOG.md +75 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/android/build.gradle +36 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/com/bgoswaldo/inappstorereview/RNInAppStoreReviewModule.kt +39 -0
- package/android/src/main/java/com/bgoswaldo/inappstorereview/RNInAppStoreReviewPackage.kt +16 -0
- package/ios/RNInAppStoreReview.m +13 -0
- package/ios/RNInAppStoreReview.swift +27 -0
- package/lib/commonjs/index.js +56 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/index.js +50 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/index.d.ts +35 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/package.json +96 -0
- package/react-native-in-app-store-review.podspec +19 -0
- package/src/index.tsx +79 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.0] - 2026-09-11
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Renombrado el paquete** de `@bgoswaldo/react-native-in-app-store-review` a
|
|
13
|
+
`@acertijosapps/react-native-in-app-store-review`. El paquete anterior queda
|
|
14
|
+
obsoleto (`npm deprecate`); actualiza el import y la dependencia al nuevo
|
|
15
|
+
nombre. El código y la API pública no cambian.
|
|
16
|
+
|
|
17
|
+
## [1.0.5] - 2026-08-18
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Mejorada la `description` de npm con términos de búsqueda (rate/review,
|
|
22
|
+
in-app) y afinados los `keywords` para descubribilidad.
|
|
23
|
+
|
|
24
|
+
## [1.0.4] - 2026-08-18
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Ampliados los `keywords` de npm para mejorar la búsqueda/descubribilidad.
|
|
29
|
+
|
|
30
|
+
## [1.0.3] - 2026-08-17
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- README: la ilustración usa la URL absoluta del raw de GitLab para que se
|
|
35
|
+
muestre en npmjs.com (las rutas relativas no se reescriben bien para GitLab).
|
|
36
|
+
|
|
37
|
+
## [1.0.2] - 2026-08-17
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Rutas del repositorio (`repository`, `homepage`, `bugs` y `s.source` del
|
|
42
|
+
podspec) apuntando al repo público `acertijoslibs/rninappstorereview`.
|
|
43
|
+
|
|
44
|
+
## [1.0.1] - 2026-08-16
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- README: ilustración del prompt nativo de reseña en iOS
|
|
49
|
+
(`SKStoreReviewController`) y Android (Play In-App Review), en
|
|
50
|
+
`assets/demo.png` / `assets/demo.svg`.
|
|
51
|
+
|
|
52
|
+
## [1.0.0] - 2026-08-12
|
|
53
|
+
|
|
54
|
+
Primera versión pública.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- API JS `requestReview(options?)`, `openStoreReview(options)` e
|
|
59
|
+
`isReviewSupported()` con tipos TypeScript.
|
|
60
|
+
- Bridge nativo iOS con `SKStoreReviewController`
|
|
61
|
+
(`RNInAppStoreReview.swift` / `.m`), expuesto como promesa.
|
|
62
|
+
- Bridge nativo Android con Play In-App Review
|
|
63
|
+
(`com.google.android.play:review-ktx`), expuesto como promesa.
|
|
64
|
+
- Fallback automático a la ficha de la tienda (App Store / Play Store) cuando el
|
|
65
|
+
módulo nativo no está enlazado.
|
|
66
|
+
- Empaquetado con `react-native-builder-bob` (salidas CommonJS, ESM y tipos) y
|
|
67
|
+
autolinking para iOS (podspec) y Android (Gradle).
|
|
68
|
+
|
|
69
|
+
[1.1.0]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.1.0
|
|
70
|
+
[1.0.5]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.5
|
|
71
|
+
[1.0.4]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.4
|
|
72
|
+
[1.0.3]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.3
|
|
73
|
+
[1.0.2]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.2
|
|
74
|
+
[1.0.1]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.1
|
|
75
|
+
[1.0.0]: https://gitlab.com/acertijoslibs/rninappstorereview/-/tags/v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 bgoswaldo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @acertijosapps/react-native-in-app-store-review
|
|
2
|
+
|
|
3
|
+
Ask users to rate your app **without leaving it**, using each platform's native
|
|
4
|
+
in-app review flow:
|
|
5
|
+
|
|
6
|
+
- **iOS** → [`SKStoreReviewController`](https://developer.apple.com/documentation/storekit/skstorereviewcontroller)
|
|
7
|
+
- **Android** → [Play In-App Review](https://developer.android.com/guide/playcore/in-app-review) (`com.google.android.play:review-ktx`)
|
|
8
|
+
|
|
9
|
+
If the native module isn't available (e.g. Expo Go, or before you rebuild), it
|
|
10
|
+
falls back to opening the store listing.
|
|
11
|
+
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
> Illustration of the native review prompt: iOS `SKStoreReviewController` (left)
|
|
15
|
+
> and Android Play In-App Review (right).
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @acertijosapps/react-native-in-app-store-review
|
|
21
|
+
# or
|
|
22
|
+
yarn add @acertijosapps/react-native-in-app-store-review
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### iOS
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
cd ios && pod install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Android
|
|
32
|
+
|
|
33
|
+
No manual steps — the module is autolinked.
|
|
34
|
+
|
|
35
|
+
> Minimum: iOS 13+, `minSdkVersion` 21+. Uses a legacy bridge module, which works
|
|
36
|
+
> under both the old and the New Architecture (via the interop layer).
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { requestReview } from '@acertijosapps/react-native-in-app-store-review';
|
|
42
|
+
|
|
43
|
+
// Call it after a positive moment in your app (task completed, level cleared…),
|
|
44
|
+
// never on app launch, and don't gate a feature behind it.
|
|
45
|
+
await requestReview({
|
|
46
|
+
iosAppId: '1234567890', // used only by the store fallback
|
|
47
|
+
androidPackage: 'com.acme.app', // used only by the store fallback
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### API
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
function requestReview(options?: RequestReviewOptions): Promise<void>;
|
|
55
|
+
function openStoreReview(options: RequestReviewOptions): Promise<void>;
|
|
56
|
+
function isReviewSupported(): boolean;
|
|
57
|
+
|
|
58
|
+
interface RequestReviewOptions {
|
|
59
|
+
iosAppId?: string; // numeric App Store id
|
|
60
|
+
androidPackage?: string; // Android application id / package name
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- **`requestReview(options?)`** — Shows the native in-app prompt. If the native
|
|
65
|
+
module is not linked, falls back to `openStoreReview(options)`.
|
|
66
|
+
- **`openStoreReview(options)`** — Explicitly opens the store listing
|
|
67
|
+
(App Store "write review" sheet on iOS, Play Store listing on Android).
|
|
68
|
+
- **`isReviewSupported()`** — `true` when the native module is linked.
|
|
69
|
+
|
|
70
|
+
## Important notes
|
|
71
|
+
|
|
72
|
+
The OS controls whether the prompt actually appears — you can call it, but there
|
|
73
|
+
is no guarantee it shows:
|
|
74
|
+
|
|
75
|
+
- **iOS**: the prompt **never** appears in debug builds or via TestFlight. Test
|
|
76
|
+
it in a production/App Store build. Apple also rate-limits it (a few times per
|
|
77
|
+
365 days per device).
|
|
78
|
+
- **Android**: Play rate-limits and may show nothing (quota). Test with an
|
|
79
|
+
internal testing track / a license-tester account. The call resolves either
|
|
80
|
+
way — treat a resolved promise as "attempted", not "shown".
|
|
81
|
+
|
|
82
|
+
Because the flow can silently do nothing, don't rely on a callback to know the
|
|
83
|
+
user reviewed, and don't block UI on it.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apply plugin: "com.android.library"
|
|
2
|
+
apply plugin: "org.jetbrains.kotlin.android"
|
|
3
|
+
|
|
4
|
+
def safeExtGet(prop, fallback) {
|
|
5
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
android {
|
|
9
|
+
namespace "com.bgoswaldo.inappstorereview"
|
|
10
|
+
|
|
11
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 35)
|
|
12
|
+
|
|
13
|
+
defaultConfig {
|
|
14
|
+
minSdkVersion safeExtGet("minSdkVersion", 24)
|
|
15
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 35)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
compileOptions {
|
|
19
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
20
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
kotlinOptions {
|
|
24
|
+
jvmTarget = "17"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
repositories {
|
|
29
|
+
mavenCentral()
|
|
30
|
+
google()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
dependencies {
|
|
34
|
+
implementation "com.facebook.react:react-android"
|
|
35
|
+
implementation "com.google.android.play:review-ktx:2.0.2"
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
package com.bgoswaldo.inappstorereview
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import com.facebook.react.bridge.Promise
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
7
|
+
import com.facebook.react.bridge.ReactMethod
|
|
8
|
+
import com.google.android.play.core.review.ReviewManagerFactory
|
|
9
|
+
|
|
10
|
+
class RNInAppStoreReviewModule(reactContext: ReactApplicationContext) :
|
|
11
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
12
|
+
|
|
13
|
+
override fun getName(): String = NAME
|
|
14
|
+
|
|
15
|
+
@ReactMethod
|
|
16
|
+
fun requestReview(promise: Promise) {
|
|
17
|
+
val activity: Activity? = currentActivity
|
|
18
|
+
if (activity == null) {
|
|
19
|
+
// No foreground activity to attach the flow to — resolve as a no-op.
|
|
20
|
+
promise.resolve(null)
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
val manager = ReviewManagerFactory.create(reactApplicationContext)
|
|
25
|
+
manager.requestReviewFlow().addOnCompleteListener { request ->
|
|
26
|
+
if (request.isSuccessful) {
|
|
27
|
+
manager.launchReviewFlow(activity, request.result)
|
|
28
|
+
.addOnCompleteListener { promise.resolve(null) }
|
|
29
|
+
} else {
|
|
30
|
+
// Play may throttle or fail to fetch the flow — treat as a no-op.
|
|
31
|
+
promise.resolve(null)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
companion object {
|
|
37
|
+
const val NAME = "RNInAppStoreReview"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.bgoswaldo.inappstorereview
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class RNInAppStoreReviewPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(
|
|
10
|
+
reactContext: ReactApplicationContext,
|
|
11
|
+
): List<NativeModule> = listOf(RNInAppStoreReviewModule(reactContext))
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(
|
|
14
|
+
reactContext: ReactApplicationContext,
|
|
15
|
+
): List<ViewManager<*, *>> = emptyList()
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
|
|
3
|
+
@interface RCT_EXTERN_MODULE(RNInAppStoreReview, NSObject)
|
|
4
|
+
|
|
5
|
+
RCT_EXTERN_METHOD(requestReview:(RCTPromiseResolveBlock)resolve
|
|
6
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
7
|
+
|
|
8
|
+
+ (BOOL)requiresMainQueueSetup
|
|
9
|
+
{
|
|
10
|
+
return YES;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
import StoreKit
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
@objc(RNInAppStoreReview)
|
|
7
|
+
class RNInAppStoreReview: NSObject {
|
|
8
|
+
@objc static func requiresMainQueueSetup() -> Bool {
|
|
9
|
+
return true
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@objc func requestReview(
|
|
13
|
+
_ resolve: @escaping RCTPromiseResolveBlock,
|
|
14
|
+
rejecter reject: @escaping RCTPromiseRejectBlock
|
|
15
|
+
) {
|
|
16
|
+
DispatchQueue.main.async {
|
|
17
|
+
if let scene = UIApplication.shared.connectedScenes.first(where: {
|
|
18
|
+
$0.activationState == .foregroundActive
|
|
19
|
+
}) as? UIWindowScene {
|
|
20
|
+
SKStoreReviewController.requestReview(in: scene)
|
|
21
|
+
} else {
|
|
22
|
+
SKStoreReviewController.requestReview()
|
|
23
|
+
}
|
|
24
|
+
resolve(nil)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isReviewSupported = isReviewSupported;
|
|
7
|
+
exports.openStoreReview = openStoreReview;
|
|
8
|
+
exports.requestReview = requestReview;
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
const nativeModule = _reactNative.NativeModules.RNInAppStoreReview;
|
|
11
|
+
/**
|
|
12
|
+
* Returns `true` when the native in-app review module is linked and available.
|
|
13
|
+
* When `false`, {@link requestReview} falls back to opening the store listing.
|
|
14
|
+
*/
|
|
15
|
+
function isReviewSupported() {
|
|
16
|
+
return nativeModule != null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Opens the platform store page as a fallback when the native in-app prompt is
|
|
21
|
+
* unavailable. On iOS it opens the App Store "write review" sheet; on Android it
|
|
22
|
+
* opens the Play Store listing. Requires the matching id in `options`; otherwise
|
|
23
|
+
* it resolves without doing anything.
|
|
24
|
+
*/
|
|
25
|
+
async function openStoreReview(options) {
|
|
26
|
+
const url = _reactNative.Platform.select({
|
|
27
|
+
ios: options.iosAppId ? `https://apps.apple.com/app/id${options.iosAppId}?action=write-review` : undefined,
|
|
28
|
+
android: options.androidPackage ? `market://details?id=${options.androidPackage}` : undefined
|
|
29
|
+
});
|
|
30
|
+
if (url == null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
await _reactNative.Linking.openURL(url);
|
|
35
|
+
} catch {
|
|
36
|
+
// Store app not available — nothing else we can do.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Requests the native in-app review prompt (iOS `SKStoreReviewController` /
|
|
42
|
+
* Android Play In-App Review). If the native module is not linked, it falls back
|
|
43
|
+
* to opening the store listing using the ids provided in `options`.
|
|
44
|
+
*
|
|
45
|
+
* Note: both platforms decide whether the prompt actually appears and rate-limit
|
|
46
|
+
* it. On iOS the prompt never shows in debug builds or via TestFlight — only in
|
|
47
|
+
* App Store production builds.
|
|
48
|
+
*/
|
|
49
|
+
async function requestReview(options = {}) {
|
|
50
|
+
if (nativeModule?.requestReview != null) {
|
|
51
|
+
await nativeModule.requestReview();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
await openStoreReview(options);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","nativeModule","NativeModules","RNInAppStoreReview","isReviewSupported","openStoreReview","options","url","Platform","select","ios","iosAppId","undefined","android","androidPackage","Linking","openURL","requestReview"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAMA,MAAMC,YAAY,GAChBC,0BAAa,CACbC,kBAAkB;AAepB;AACA;AACA;AACA;AACO,SAASC,iBAAiBA,CAAA,EAAY;EAC3C,OAAOH,YAAY,IAAI,IAAI;AAC7B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeI,eAAeA,CACnCC,OAA6B,EACd;EACf,MAAMC,GAAG,GAAGC,qBAAQ,CAACC,MAAM,CAAC;IAC1BC,GAAG,EAAEJ,OAAO,CAACK,QAAQ,GACjB,gCAAgCL,OAAO,CAACK,QAAQ,sBAAsB,GACtEC,SAAS;IACbC,OAAO,EAAEP,OAAO,CAACQ,cAAc,GAC3B,uBAAuBR,OAAO,CAACQ,cAAc,EAAE,GAC/CF;EACN,CAAC,CAAC;EAEF,IAAIL,GAAG,IAAI,IAAI,EAAE;IACf;EACF;EAEA,IAAI;IACF,MAAMQ,oBAAO,CAACC,OAAO,CAACT,GAAG,CAAC;EAC5B,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeU,aAAaA,CACjCX,OAA6B,GAAG,CAAC,CAAC,EACnB;EACf,IAAIL,YAAY,EAAEgB,aAAa,IAAI,IAAI,EAAE;IACvC,MAAMhB,YAAY,CAACgB,aAAa,CAAC,CAAC;IAClC;EACF;EAEA,MAAMZ,eAAe,CAACC,OAAO,CAAC;AAChC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Linking, NativeModules, Platform } from 'react-native';
|
|
4
|
+
const nativeModule = NativeModules.RNInAppStoreReview;
|
|
5
|
+
/**
|
|
6
|
+
* Returns `true` when the native in-app review module is linked and available.
|
|
7
|
+
* When `false`, {@link requestReview} falls back to opening the store listing.
|
|
8
|
+
*/
|
|
9
|
+
export function isReviewSupported() {
|
|
10
|
+
return nativeModule != null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Opens the platform store page as a fallback when the native in-app prompt is
|
|
15
|
+
* unavailable. On iOS it opens the App Store "write review" sheet; on Android it
|
|
16
|
+
* opens the Play Store listing. Requires the matching id in `options`; otherwise
|
|
17
|
+
* it resolves without doing anything.
|
|
18
|
+
*/
|
|
19
|
+
export async function openStoreReview(options) {
|
|
20
|
+
const url = Platform.select({
|
|
21
|
+
ios: options.iosAppId ? `https://apps.apple.com/app/id${options.iosAppId}?action=write-review` : undefined,
|
|
22
|
+
android: options.androidPackage ? `market://details?id=${options.androidPackage}` : undefined
|
|
23
|
+
});
|
|
24
|
+
if (url == null) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
await Linking.openURL(url);
|
|
29
|
+
} catch {
|
|
30
|
+
// Store app not available — nothing else we can do.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Requests the native in-app review prompt (iOS `SKStoreReviewController` /
|
|
36
|
+
* Android Play In-App Review). If the native module is not linked, it falls back
|
|
37
|
+
* to opening the store listing using the ids provided in `options`.
|
|
38
|
+
*
|
|
39
|
+
* Note: both platforms decide whether the prompt actually appears and rate-limit
|
|
40
|
+
* it. On iOS the prompt never shows in debug builds or via TestFlight — only in
|
|
41
|
+
* App Store production builds.
|
|
42
|
+
*/
|
|
43
|
+
export async function requestReview(options = {}) {
|
|
44
|
+
if (nativeModule?.requestReview != null) {
|
|
45
|
+
await nativeModule.requestReview();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await openStoreReview(options);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Linking","NativeModules","Platform","nativeModule","RNInAppStoreReview","isReviewSupported","openStoreReview","options","url","select","ios","iosAppId","undefined","android","androidPackage","openURL","requestReview"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,OAAO,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAM/D,MAAMC,YAAY,GAChBF,aAAa,CACbG,kBAAkB;AAepB;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAY;EAC3C,OAAOF,YAAY,IAAI,IAAI;AAC7B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeG,eAAeA,CACnCC,OAA6B,EACd;EACf,MAAMC,GAAG,GAAGN,QAAQ,CAACO,MAAM,CAAC;IAC1BC,GAAG,EAAEH,OAAO,CAACI,QAAQ,GACjB,gCAAgCJ,OAAO,CAACI,QAAQ,sBAAsB,GACtEC,SAAS;IACbC,OAAO,EAAEN,OAAO,CAACO,cAAc,GAC3B,uBAAuBP,OAAO,CAACO,cAAc,EAAE,GAC/CF;EACN,CAAC,CAAC;EAEF,IAAIJ,GAAG,IAAI,IAAI,EAAE;IACf;EACF;EAEA,IAAI;IACF,MAAMR,OAAO,CAACe,OAAO,CAACP,GAAG,CAAC;EAC5B,CAAC,CAAC,MAAM;IACN;EAAA;AAEJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeQ,aAAaA,CACjCT,OAA6B,GAAG,CAAC,CAAC,EACnB;EACf,IAAIJ,YAAY,EAAEa,aAAa,IAAI,IAAI,EAAE;IACvC,MAAMb,YAAY,CAACa,aAAa,CAAC,CAAC;IAClC;EACF;EAEA,MAAMV,eAAe,CAACC,OAAO,CAAC;AAChC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface RequestReviewOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Numeric App Store app id (e.g. "1234567890"). Used only by the store
|
|
4
|
+
* fallback on iOS when the native module is unavailable.
|
|
5
|
+
*/
|
|
6
|
+
iosAppId?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Android application id / package name (e.g. "com.acme.app"). Used only by
|
|
9
|
+
* the store fallback on Android when the native module is unavailable.
|
|
10
|
+
*/
|
|
11
|
+
androidPackage?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns `true` when the native in-app review module is linked and available.
|
|
15
|
+
* When `false`, {@link requestReview} falls back to opening the store listing.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isReviewSupported(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Opens the platform store page as a fallback when the native in-app prompt is
|
|
20
|
+
* unavailable. On iOS it opens the App Store "write review" sheet; on Android it
|
|
21
|
+
* opens the Play Store listing. Requires the matching id in `options`; otherwise
|
|
22
|
+
* it resolves without doing anything.
|
|
23
|
+
*/
|
|
24
|
+
export declare function openStoreReview(options: RequestReviewOptions): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Requests the native in-app review prompt (iOS `SKStoreReviewController` /
|
|
27
|
+
* Android Play In-App Review). If the native module is not linked, it falls back
|
|
28
|
+
* to opening the store listing using the ids provided in `options`.
|
|
29
|
+
*
|
|
30
|
+
* Note: both platforms decide whether the prompt actually appears and rate-limit
|
|
31
|
+
* it. On iOS the prompt never shows in debug builds or via TestFlight — only in
|
|
32
|
+
* App Store production builds.
|
|
33
|
+
*/
|
|
34
|
+
export declare function requestReview(options?: RequestReviewOptions): Promise<void>;
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@acertijosapps/react-native-in-app-store-review",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Ask users to rate and review your React Native app in-app — native iOS (SKStoreReviewController) and Android (Play In-App Review) prompts, with an App Store / Play Store fallback.",
|
|
5
|
+
"main": "lib/commonjs/index.js",
|
|
6
|
+
"module": "lib/module/index.js",
|
|
7
|
+
"types": "lib/typescript/index.d.ts",
|
|
8
|
+
"react-native": "src/index.tsx",
|
|
9
|
+
"source": "src/index.tsx",
|
|
10
|
+
"files": [
|
|
11
|
+
"src",
|
|
12
|
+
"lib",
|
|
13
|
+
"android",
|
|
14
|
+
"ios",
|
|
15
|
+
"*.podspec",
|
|
16
|
+
"README.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"!**/__tests__",
|
|
20
|
+
"!**/__fixtures__",
|
|
21
|
+
"!**/__mocks__",
|
|
22
|
+
"!android/build",
|
|
23
|
+
"!android/.gradle"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"prepare": "bob build",
|
|
27
|
+
"typecheck": "tsc --noEmit"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"react-native",
|
|
31
|
+
"react-native-in-app-store-review",
|
|
32
|
+
"react-native-in-app-review",
|
|
33
|
+
"react-native-store-review",
|
|
34
|
+
"ios",
|
|
35
|
+
"android",
|
|
36
|
+
"expo",
|
|
37
|
+
"review",
|
|
38
|
+
"reviews",
|
|
39
|
+
"rating",
|
|
40
|
+
"ratings",
|
|
41
|
+
"rate",
|
|
42
|
+
"rate-app",
|
|
43
|
+
"rate-us",
|
|
44
|
+
"app-review",
|
|
45
|
+
"app-rating",
|
|
46
|
+
"in-app-review",
|
|
47
|
+
"in-app-rating",
|
|
48
|
+
"store-review",
|
|
49
|
+
"app-store",
|
|
50
|
+
"appstore",
|
|
51
|
+
"play-store",
|
|
52
|
+
"google-play",
|
|
53
|
+
"storekit",
|
|
54
|
+
"SKStoreReviewController",
|
|
55
|
+
"play-core"
|
|
56
|
+
],
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://gitlab.com/acertijoslibs/rninappstorereview.git"
|
|
60
|
+
},
|
|
61
|
+
"author": "bgoswaldo <bgoswaldo@gmail.com>",
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"homepage": "https://gitlab.com/acertijoslibs/rninappstorereview#readme",
|
|
64
|
+
"bugs": {
|
|
65
|
+
"url": "https://gitlab.com/acertijoslibs/rninappstorereview/-/issues"
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"react": "*",
|
|
72
|
+
"react-native": "*"
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@react-native/babel-preset": "0.86.0",
|
|
76
|
+
"@types/react": "^19.0.0",
|
|
77
|
+
"react": "19.2.3",
|
|
78
|
+
"react-native": "0.86.0",
|
|
79
|
+
"react-native-builder-bob": "^0.35.0",
|
|
80
|
+
"typescript": "^5.8.3"
|
|
81
|
+
},
|
|
82
|
+
"react-native-builder-bob": {
|
|
83
|
+
"source": "src",
|
|
84
|
+
"output": "lib",
|
|
85
|
+
"targets": [
|
|
86
|
+
"commonjs",
|
|
87
|
+
"module",
|
|
88
|
+
[
|
|
89
|
+
"typescript",
|
|
90
|
+
{
|
|
91
|
+
"project": "tsconfig.build.json"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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 = "react-native-in-app-store-review"
|
|
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
|
+
s.platforms = { :ios => "13.0" }
|
|
13
|
+
s.source = { :git => "https://gitlab.com/acertijoslibs/rninappstorereview.git", :tag => "#{s.version}" }
|
|
14
|
+
|
|
15
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
16
|
+
s.frameworks = "StoreKit"
|
|
17
|
+
|
|
18
|
+
install_modules_dependencies(s)
|
|
19
|
+
end
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Linking, NativeModules, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
interface NativeReviewModule {
|
|
4
|
+
requestReview: () => Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const nativeModule = (
|
|
8
|
+
NativeModules as { RNInAppStoreReview?: NativeReviewModule }
|
|
9
|
+
).RNInAppStoreReview;
|
|
10
|
+
|
|
11
|
+
export interface RequestReviewOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Numeric App Store app id (e.g. "1234567890"). Used only by the store
|
|
14
|
+
* fallback on iOS when the native module is unavailable.
|
|
15
|
+
*/
|
|
16
|
+
iosAppId?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Android application id / package name (e.g. "com.acme.app"). Used only by
|
|
19
|
+
* the store fallback on Android when the native module is unavailable.
|
|
20
|
+
*/
|
|
21
|
+
androidPackage?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns `true` when the native in-app review module is linked and available.
|
|
26
|
+
* When `false`, {@link requestReview} falls back to opening the store listing.
|
|
27
|
+
*/
|
|
28
|
+
export function isReviewSupported(): boolean {
|
|
29
|
+
return nativeModule != null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Opens the platform store page as a fallback when the native in-app prompt is
|
|
34
|
+
* unavailable. On iOS it opens the App Store "write review" sheet; on Android it
|
|
35
|
+
* opens the Play Store listing. Requires the matching id in `options`; otherwise
|
|
36
|
+
* it resolves without doing anything.
|
|
37
|
+
*/
|
|
38
|
+
export async function openStoreReview(
|
|
39
|
+
options: RequestReviewOptions,
|
|
40
|
+
): Promise<void> {
|
|
41
|
+
const url = Platform.select({
|
|
42
|
+
ios: options.iosAppId
|
|
43
|
+
? `https://apps.apple.com/app/id${options.iosAppId}?action=write-review`
|
|
44
|
+
: undefined,
|
|
45
|
+
android: options.androidPackage
|
|
46
|
+
? `market://details?id=${options.androidPackage}`
|
|
47
|
+
: undefined,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (url == null) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await Linking.openURL(url);
|
|
56
|
+
} catch {
|
|
57
|
+
// Store app not available — nothing else we can do.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Requests the native in-app review prompt (iOS `SKStoreReviewController` /
|
|
63
|
+
* Android Play In-App Review). If the native module is not linked, it falls back
|
|
64
|
+
* to opening the store listing using the ids provided in `options`.
|
|
65
|
+
*
|
|
66
|
+
* Note: both platforms decide whether the prompt actually appears and rate-limit
|
|
67
|
+
* it. On iOS the prompt never shows in debug builds or via TestFlight — only in
|
|
68
|
+
* App Store production builds.
|
|
69
|
+
*/
|
|
70
|
+
export async function requestReview(
|
|
71
|
+
options: RequestReviewOptions = {},
|
|
72
|
+
): Promise<void> {
|
|
73
|
+
if (nativeModule?.requestReview != null) {
|
|
74
|
+
await nativeModule.requestReview();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await openStoreReview(options);
|
|
79
|
+
}
|