@cap-kit/rank 8.0.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/CapKitRank.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +574 -0
- package/android/build.gradle +110 -0
- package/android/src/main/AndroidManifest.xml +16 -0
- package/android/src/main/java/io/capkit/rank/RankConfig.kt +72 -0
- package/android/src/main/java/io/capkit/rank/RankError.kt +40 -0
- package/android/src/main/java/io/capkit/rank/RankImpl.kt +240 -0
- package/android/src/main/java/io/capkit/rank/RankPlugin.kt +312 -0
- package/android/src/main/java/io/capkit/rank/utils/RankLogger.kt +85 -0
- package/android/src/main/java/io/capkit/rank/utils/RankUtils.kt +14 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +441 -0
- package/dist/esm/definitions.d.ts +330 -0
- package/dist/esm/definitions.js +21 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +19 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +81 -0
- package/dist/esm/web.js +157 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +204 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +207 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/RankPlugin/RankConfig.swift +89 -0
- package/ios/Sources/RankPlugin/RankError.swift +49 -0
- package/ios/Sources/RankPlugin/RankImpl.swift +186 -0
- package/ios/Sources/RankPlugin/RankPlugin.swift +258 -0
- package/ios/Sources/RankPlugin/Utils/RankLogger.swift +69 -0
- package/ios/Sources/RankPlugin/Utils/RankUtils.swift +45 -0
- package/ios/Sources/RankPlugin/Version.swift +16 -0
- package/ios/Tests/RankPluginTests/RankPluginTests.swift +10 -0
- package/package.json +102 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20'
|
|
3
|
+
repositories {
|
|
4
|
+
google()
|
|
5
|
+
mavenCentral()
|
|
6
|
+
}
|
|
7
|
+
dependencies {
|
|
8
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
9
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
plugins {
|
|
14
|
+
id "org.jlleitschuh.gradle.ktlint" version "12.1.1" apply false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ext {
|
|
18
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
19
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
20
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
|
21
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
22
|
+
androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.17.0'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
apply plugin: 'com.android.library'
|
|
26
|
+
apply plugin: 'kotlin-android'
|
|
27
|
+
apply plugin: 'kotlin-parcelize'
|
|
28
|
+
apply plugin: 'org.jlleitschuh.gradle.ktlint'
|
|
29
|
+
|
|
30
|
+
import groovy.json.JsonSlurper
|
|
31
|
+
|
|
32
|
+
def getPluginVersion() {
|
|
33
|
+
try {
|
|
34
|
+
def packageJsonFile = file('../package.json')
|
|
35
|
+
if (packageJsonFile.exists()) {
|
|
36
|
+
def packageJson = new JsonSlurper().parseText(packageJsonFile.text)
|
|
37
|
+
return packageJson.version
|
|
38
|
+
}
|
|
39
|
+
} catch (Exception e) {
|
|
40
|
+
// Ignore errors and fallback
|
|
41
|
+
logger.info("Exception", e)
|
|
42
|
+
}
|
|
43
|
+
return "8.0.0"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def pluginVersion = getPluginVersion()
|
|
47
|
+
|
|
48
|
+
android {
|
|
49
|
+
namespace = "io.capkit.rank"
|
|
50
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion as Integer : 36
|
|
51
|
+
|
|
52
|
+
// AGP 8.0+ disables BuildConfig by default for libraries.
|
|
53
|
+
// We need to enable it to inject the plugin version.
|
|
54
|
+
buildFeatures {
|
|
55
|
+
buildConfig = true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
defaultConfig {
|
|
59
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion as Integer : 24
|
|
60
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion as Integer : 36
|
|
61
|
+
versionCode 1
|
|
62
|
+
|
|
63
|
+
// Dynamic versioning (feature enabled)
|
|
64
|
+
versionName = pluginVersion
|
|
65
|
+
|
|
66
|
+
// Injects the version into the BuildConfig class ONLY if feature is enabled
|
|
67
|
+
buildConfigField "String", "PLUGIN_VERSION", "\"${pluginVersion}\""
|
|
68
|
+
|
|
69
|
+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
70
|
+
}
|
|
71
|
+
buildTypes {
|
|
72
|
+
release {
|
|
73
|
+
minifyEnabled = false
|
|
74
|
+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
lint {
|
|
78
|
+
abortOnError = false
|
|
79
|
+
}
|
|
80
|
+
compileOptions {
|
|
81
|
+
sourceCompatibility = JavaVersion.VERSION_21
|
|
82
|
+
targetCompatibility = JavaVersion.VERSION_21
|
|
83
|
+
}
|
|
84
|
+
kotlinOptions {
|
|
85
|
+
jvmTarget = JavaVersion.VERSION_21
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
repositories {
|
|
90
|
+
google()
|
|
91
|
+
mavenCentral()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
dependencies {
|
|
95
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
96
|
+
implementation project(':capacitor-android')
|
|
97
|
+
|
|
98
|
+
// Google Play Review Library
|
|
99
|
+
implementation "com.google.android.play:review:2.0.2"
|
|
100
|
+
// Kotlin extension for ReviewManager
|
|
101
|
+
implementation "com.google.android.play:review-ktx:2.0.2"
|
|
102
|
+
|
|
103
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
104
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
105
|
+
implementation "androidx.core:core-ktx:$androidxCoreKTXVersion"
|
|
106
|
+
|
|
107
|
+
testImplementation "junit:junit:$junitVersion"
|
|
108
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
109
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
110
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
3
|
+
<queries>
|
|
4
|
+
<intent>
|
|
5
|
+
<action android:name="android.intent.action.VIEW" />
|
|
6
|
+
<data android:scheme="market" />
|
|
7
|
+
</intent>
|
|
8
|
+
<intent>
|
|
9
|
+
<action android:name="android.intent.action.VIEW" />
|
|
10
|
+
<data android:scheme="https" android:host="play.google.com" />
|
|
11
|
+
</intent>
|
|
12
|
+
</queries>
|
|
13
|
+
|
|
14
|
+
<application>
|
|
15
|
+
</application>
|
|
16
|
+
</manifest>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
package io.capkit.rank
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.getcapacitor.Plugin
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Plugin configuration holder for the Rank plugin.
|
|
8
|
+
*
|
|
9
|
+
* This class is responsible for reading and parsing static configuration values
|
|
10
|
+
* defined under the `plugins.Rank` key in `capacitor.config.ts`.
|
|
11
|
+
*
|
|
12
|
+
* Architectural rules:
|
|
13
|
+
* - Read once during plugin initialization in the load() phase.
|
|
14
|
+
* - Configuration values are read-only at runtime.
|
|
15
|
+
* - Consumed only by native code.
|
|
16
|
+
*/
|
|
17
|
+
class RankConfig(plugin: Plugin) {
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Properties
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Android application context.
|
|
24
|
+
* Accessible for native implementation components that require system services.
|
|
25
|
+
*/
|
|
26
|
+
val context: Context = plugin.context
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Enables verbose native logging via RankLogger.
|
|
30
|
+
*
|
|
31
|
+
* When true, additional debug information and lifecycle events are printed to Logcat.
|
|
32
|
+
* Default: false
|
|
33
|
+
*/
|
|
34
|
+
val verboseLogging: Boolean
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The Android Package Name used for Play Store redirection.
|
|
38
|
+
*
|
|
39
|
+
* If provided, this value overrides the host application's package name
|
|
40
|
+
* during store navigation.
|
|
41
|
+
* Default: null (falls back to host app package)
|
|
42
|
+
*/
|
|
43
|
+
val androidPackageName: String?
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Global policy for review request resolution.
|
|
47
|
+
*
|
|
48
|
+
* If true, the `requestReview` method resolves the promise immediately
|
|
49
|
+
* without waiting for the Google Play review flow to complete.
|
|
50
|
+
* Default: false
|
|
51
|
+
*/
|
|
52
|
+
val fireAndForget: Boolean
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Initialization
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
init {
|
|
59
|
+
// Access the plugin-specific configuration object
|
|
60
|
+
val config = plugin.getConfig()
|
|
61
|
+
|
|
62
|
+
// Extract verboseLogging flag
|
|
63
|
+
verboseLogging = config.getBoolean("verboseLogging", false)
|
|
64
|
+
|
|
65
|
+
// Extract and validate the Android Package Name
|
|
66
|
+
val apm = config.getString("androidPackageName")
|
|
67
|
+
androidPackageName = if (!apm.isNullOrBlank()) apm else null
|
|
68
|
+
|
|
69
|
+
// Extract the fireAndForget resolution policy
|
|
70
|
+
fireAndForget = config.getBoolean("fireAndForget", false)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package io.capkit.rank
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Native error model for the Rank plugin (Android).
|
|
5
|
+
*
|
|
6
|
+
* Architectural rules:
|
|
7
|
+
* - Must NOT reference Capacitor APIs
|
|
8
|
+
* - Must NOT reference JavaScript
|
|
9
|
+
* - Must be throwable from the Impl layer
|
|
10
|
+
* - Mapping to JS-facing error codes happens ONLY in the Plugin layer
|
|
11
|
+
*/
|
|
12
|
+
sealed class RankError(
|
|
13
|
+
message: String,
|
|
14
|
+
) : Throwable(message) {
|
|
15
|
+
/**
|
|
16
|
+
* Feature or capability is not available
|
|
17
|
+
* due to device or configuration limitations.
|
|
18
|
+
*/
|
|
19
|
+
class Unavailable(message: String) :
|
|
20
|
+
RankError(message)
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Required permission was denied or not granted.
|
|
24
|
+
*/
|
|
25
|
+
class PermissionDenied(message: String) :
|
|
26
|
+
RankError(message)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Plugin failed to initialize or perform
|
|
30
|
+
* a required operation.
|
|
31
|
+
*/
|
|
32
|
+
class InitFailed(message: String) :
|
|
33
|
+
RankError(message)
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Invalid or unsupported input was provided.
|
|
37
|
+
*/
|
|
38
|
+
class UnknownType(message: String) :
|
|
39
|
+
RankError(message)
|
|
40
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
package io.capkit.rank
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.content.Intent
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import com.google.android.play.core.review.ReviewManagerFactory
|
|
8
|
+
import io.capkit.rank.utils.RankLogger
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Platform-specific native implementation for the Rank plugin.
|
|
12
|
+
*
|
|
13
|
+
* This class contains pure Android logic and MUST NOT depend directly on
|
|
14
|
+
* Capacitor bridge APIs or PluginCall objects.
|
|
15
|
+
*
|
|
16
|
+
* Responsibilities:
|
|
17
|
+
* - Orchestrating the Google Play Review SDK.
|
|
18
|
+
* - Managing Intent-based Store navigation.
|
|
19
|
+
* - Translating configuration into native behavior.
|
|
20
|
+
*/
|
|
21
|
+
class RankImpl(
|
|
22
|
+
private val context: Context,
|
|
23
|
+
) {
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Properties
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Cached plugin configuration container.
|
|
30
|
+
* Provided once during initialization via [updateConfig].
|
|
31
|
+
*/
|
|
32
|
+
private lateinit var config: RankConfig
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Configuration
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Applies the plugin configuration to the implementation layer.
|
|
40
|
+
*
|
|
41
|
+
* This method MUST be called exactly once during the plugin [RankPlugin.load]
|
|
42
|
+
* phase. It initializes internal state and configures logging verbosity.
|
|
43
|
+
*
|
|
44
|
+
* @param newConfig The immutable configuration instance.
|
|
45
|
+
*/
|
|
46
|
+
fun updateConfig(newConfig: RankConfig) {
|
|
47
|
+
this.config = newConfig
|
|
48
|
+
RankLogger.verbose = newConfig.verboseLogging
|
|
49
|
+
RankLogger.debug(
|
|
50
|
+
"Configuration applied. Verbose logging:",
|
|
51
|
+
newConfig.verboseLogging.toString(),
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Availability check
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Checks whether the In-App Review feature is available on this device.
|
|
61
|
+
*
|
|
62
|
+
* This is a semantic availability check intended for UI decisions.
|
|
63
|
+
* Internally, it delegates to the diagnostic environment check.
|
|
64
|
+
*/
|
|
65
|
+
fun isAvailable(onResult: (Boolean) -> Unit) {
|
|
66
|
+
checkReviewEnvironment { canRequest ->
|
|
67
|
+
onResult(canRequest)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Performs a diagnostic check for the Google Play Review environment.
|
|
73
|
+
*
|
|
74
|
+
* This verifies whether Google Play Services can provide
|
|
75
|
+
* a ReviewInfo instance for the current application and device.
|
|
76
|
+
*
|
|
77
|
+
* No UI is triggered by this operation.
|
|
78
|
+
*/
|
|
79
|
+
fun checkReviewEnvironment(onResult: (Boolean) -> Unit) {
|
|
80
|
+
val manager = ReviewManagerFactory.create(context)
|
|
81
|
+
val request = manager.requestReviewFlow()
|
|
82
|
+
|
|
83
|
+
request.addOnCompleteListener { task ->
|
|
84
|
+
onResult(task.isSuccessful)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Pre-warm Logic
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Cached ReviewInfo object to speed up the review flow display.
|
|
94
|
+
*/
|
|
95
|
+
private var cachedReviewInfo: com.google.android.play.core.review.ReviewInfo? = null
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Pre-fetches the ReviewInfo from Google Play Services.
|
|
99
|
+
* This should be called early (e.g., during plugin load).
|
|
100
|
+
*/
|
|
101
|
+
fun preloadReviewInfo() {
|
|
102
|
+
val manager = ReviewManagerFactory.create(context)
|
|
103
|
+
val request = manager.requestReviewFlow()
|
|
104
|
+
request.addOnCompleteListener { task ->
|
|
105
|
+
if (task.isSuccessful) {
|
|
106
|
+
cachedReviewInfo = task.result
|
|
107
|
+
RankLogger.debug("ReviewInfo pre-loaded successfully.")
|
|
108
|
+
} else {
|
|
109
|
+
RankLogger.debug("ReviewInfo pre-load failed.")
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
// In-App Review Logic
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Triggers the Google Play In-App Review flow.
|
|
120
|
+
* Uses the cached ReviewInfo if available to ensure an immediate prompt.
|
|
121
|
+
*
|
|
122
|
+
* @param activity The current Android Activity required to display the UI.
|
|
123
|
+
* @param onComplete Callback invoked when the flow completes or fails.
|
|
124
|
+
*/
|
|
125
|
+
fun requestReview(
|
|
126
|
+
activity: Activity,
|
|
127
|
+
onComplete: (Exception?) -> Unit,
|
|
128
|
+
) {
|
|
129
|
+
val manager = ReviewManagerFactory.create(context)
|
|
130
|
+
|
|
131
|
+
// Use cache if available, otherwise fetch new info on the fly
|
|
132
|
+
if (cachedReviewInfo != null) {
|
|
133
|
+
val flow = manager.launchReviewFlow(activity, cachedReviewInfo!!)
|
|
134
|
+
flow.addOnCompleteListener { _ ->
|
|
135
|
+
cachedReviewInfo = null // Clear cache after use to prevent reuse of expired info
|
|
136
|
+
onComplete(null)
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
val request = manager.requestReviewFlow()
|
|
140
|
+
request.addOnCompleteListener { task ->
|
|
141
|
+
if (task.isSuccessful) {
|
|
142
|
+
val reviewInfo = task.result
|
|
143
|
+
val flow = manager.launchReviewFlow(activity, reviewInfo)
|
|
144
|
+
flow.addOnCompleteListener { _ -> onComplete(null) }
|
|
145
|
+
} else {
|
|
146
|
+
onComplete(task.exception)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Store Navigation Logic
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Opens the Google Play Store page for the specified package.
|
|
158
|
+
*
|
|
159
|
+
* It attempts to use the "market://" URI scheme first to open the native
|
|
160
|
+
* Play Store app. If the app is missing, it falls back to a browser-based
|
|
161
|
+
* "https://" URL.
|
|
162
|
+
*
|
|
163
|
+
* @param packageName The application package name. Defaults to the host app if null.
|
|
164
|
+
*/
|
|
165
|
+
fun openStore(packageName: String?) {
|
|
166
|
+
val targetPackage = packageName ?: context.packageName
|
|
167
|
+
|
|
168
|
+
// Construct the native market Intent
|
|
169
|
+
val intent =
|
|
170
|
+
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$targetPackage")).apply {
|
|
171
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
context.startActivity(intent)
|
|
176
|
+
} catch (e: Exception) {
|
|
177
|
+
// Fallback to web browser if Play Store application is unavailable
|
|
178
|
+
val webIntent =
|
|
179
|
+
Intent(
|
|
180
|
+
Intent.ACTION_VIEW,
|
|
181
|
+
Uri.parse("https://play.google.com/store/apps/details?id=$targetPackage"),
|
|
182
|
+
).apply {
|
|
183
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
184
|
+
}
|
|
185
|
+
context.startActivity(webIntent)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Opens the Google Play Store listing for a specific application ID.
|
|
191
|
+
*
|
|
192
|
+
* @param appId The Android package name or application ID to display.
|
|
193
|
+
*/
|
|
194
|
+
fun openStoreListing(appId: String) {
|
|
195
|
+
val intent =
|
|
196
|
+
Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$appId")).apply {
|
|
197
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
198
|
+
}
|
|
199
|
+
context.startActivity(intent)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Launches the Google Play Store search results for the provided terms.
|
|
204
|
+
*
|
|
205
|
+
* @param terms The search query string.
|
|
206
|
+
*/
|
|
207
|
+
fun search(terms: String) {
|
|
208
|
+
val intent =
|
|
209
|
+
Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=$terms")).apply {
|
|
210
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
211
|
+
}
|
|
212
|
+
context.startActivity(intent)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Navigates to a specific developer's page on the Google Play Store.
|
|
217
|
+
*
|
|
218
|
+
* @param devId The unique developer identifier (numeric or string ID).
|
|
219
|
+
*/
|
|
220
|
+
fun openDevPage(devId: String) {
|
|
221
|
+
val intent =
|
|
222
|
+
Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/dev?id=$devId")).apply {
|
|
223
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
224
|
+
}
|
|
225
|
+
context.startActivity(intent)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Opens a curated collection or category on the Google Play Store.
|
|
230
|
+
*
|
|
231
|
+
* @param name The collection identifier (e.g., "featured", "editors_choice").
|
|
232
|
+
*/
|
|
233
|
+
fun openCollection(name: String) {
|
|
234
|
+
val intent =
|
|
235
|
+
Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/collection/$name")).apply {
|
|
236
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
237
|
+
}
|
|
238
|
+
context.startActivity(intent)
|
|
239
|
+
}
|
|
240
|
+
}
|