diff --git a/OAT.xml b/OAT.xml
index e6853d4d5cb369825a92b3423ecc851355d2a781..6c97f87cc99d3191bec3ea358eb97e1856f8ce62 100644
--- a/OAT.xml
+++ b/OAT.xml
@@ -59,6 +59,22 @@
name="Hunan OpenValley Digital Industry Development Co., Ltd."
path=".*"
rule="may"
+ type="copyright"/>
+
+
-
-
+
+
@@ -286,6 +302,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
index 652ebc3b46e50d9234e0b6964e6a2e0beea2d3ac..c9dd5bd0fb1503206e05ea62a937175c56abbf46 100644
--- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
+++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.1.11
+
+* Updates documentation reference of `finishPurchase` to `completePurchase`.
+
## 3.1.10
* Updates example code for current versions of Flutter.
diff --git a/packages/in_app_purchase/in_app_purchase/README.md b/packages/in_app_purchase/in_app_purchase/README.md
index 59cb2c2dd9a8af2c90092cc2cd8ea67ccc6519e4..f33c4d30cf11ed8f07136b4a7cb1a3f3192c04f8 100644
--- a/packages/in_app_purchase/in_app_purchase/README.md
+++ b/packages/in_app_purchase/in_app_purchase/README.md
@@ -5,6 +5,23 @@ A storefront-independent API for purchases in Flutter apps.
This plugin supports in-app purchases (_IAP_) through an _underlying store_,
which can be the App Store (on iOS and macOS) or Google Play (on Android).
+
+
+#### ohos ˵
+
+ohos ƽ̨Ŀǰӿڣ
+
+* purchaseStream
+* isAvailable
+* queryProductDetails
+* buyNonConsumable
+* buyConsumable
+* completePurchase
+
+Ŀǰ֧ûӦóдָֻ֧̣֧ȹܣδ
+
+
+
| | Android | iOS | macOS |
|-------------|---------|-------|--------|
| **Support** | SDK 16+ | 11.0+ | 10.15+ |
diff --git a/packages/in_app_purchase/in_app_purchase/example/lib/main.dart b/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
index 5afb52ac99ea2b5045158ddad1ff54f6f480fbb4..c60f060c1b04f129282a8c497a3217cbdbb52abd 100644
--- a/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
+++ b/packages/in_app_purchase/in_app_purchase/example/lib/main.dart
@@ -92,6 +92,7 @@ class _MyAppState extends State<_MyApp> {
final ProductDetailsResponse productDetailResponse =
await _inAppPurchase.queryProductDetails(_kProductIds.toSet());
+ var productDetails = productDetailResponse.productDetails;
if (productDetailResponse.error != null) {
setState(() {
_queryProductError = productDetailResponse.error!.message;
@@ -149,13 +150,18 @@ class _MyAppState extends State<_MyApp> {
if (_queryProductError == null) {
stack.add(
ListView(
- children: [
- _buildConnectionCheckTile(),
- _buildProductList(),
- _buildConsumableBox(),
- _buildRestoreButton(),
- ],
- ),
+ children: Platform.operatingSystem == 'ohos'
+ ? [
+ _buildConnectionCheckTile(),
+ _buildProductList(),
+ _buildConsumableBox(),
+ ]
+ : [
+ _buildConnectionCheckTile(),
+ _buildProductList(),
+ _buildConsumableBox(),
+ _buildRestoreButton(),
+ ]),
);
} else {
stack.add(Center(
@@ -164,7 +170,7 @@ class _MyAppState extends State<_MyApp> {
}
if (_purchasePending) {
stack.add(
- const Stack(
+ Stack(
children: [
Opacity(
opacity: 0.3,
@@ -259,10 +265,12 @@ class _MyAppState extends State<_MyApp> {
subtitle: Text(
productDetails.description,
),
- trailing: previousPurchase != null && Platform.isIOS
- ? IconButton(
- onPressed: () => confirmPriceChange(context),
- icon: const Icon(Icons.upgrade))
+ trailing: previousPurchase != null
+ ? Platform.isIOS
+ ? IconButton(
+ onPressed: () => confirmPriceChange(context),
+ icon: const Icon(Icons.upgrade))
+ : SizedBox.shrink()
: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.green[800],
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/.gitignore b/packages/in_app_purchase/in_app_purchase/example/ohos/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6ca13b3170eec5dd5ac5ad7f1c4dd0118845f473
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/.gitignore
@@ -0,0 +1,19 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+*.har
+**/BuildProfile.ets
+**/oh-package-lock.json5
+
+**/src/main/resources/rawfile/flutter_assets/
+**/libs/arm64-v8a/libapp.so
+**/libs/arm64-v8a/libflutter.so
+**/libs/arm64-v8a/libvmservice_snapshot.so
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/app.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..a13c8bfdc16a34697a1ce5c7dc8e207275149473
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.example.in_app_purchase_ohos",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..810f4a362c1d177309eec4f2efe5cac2f4558c28
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "example"
+ }
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/media/app_icon.png b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase/example/ohos/AppScope/resources/base/media/app_icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/build-profile.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..1d12140d202702d7c73d64f1b291fe5c45a660ce
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/build-profile.json5
@@ -0,0 +1,27 @@
+{
+ "app": {
+ "signingConfigs": [],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.0(12)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/.gitignore b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2795a1c5b1fe53659dd1b71d90ba0592eaf7e043
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/.gitignore
@@ -0,0 +1,7 @@
+
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/build-profile.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..633d360fbc91a3186a23b66ab71b27e5618944cb
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/build-profile.json5
@@ -0,0 +1,29 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "apiType": 'stageMode',
+ "buildOption": {
+ },
+ "targets": [
+ {
+ "name": "default",
+ "runtimeOS": "HarmonyOS"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/hvigorfile.ts b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..894fc15c6b793f085e6c8506e43d719af658e8ff
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/hvigorfile.ts
@@ -0,0 +1,17 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { hapTasks } from '@ohos/hvigor-ohos-plugin';
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/oh-package.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..ebe795339873776bf5a6f746d1f6d1351f208c1f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/oh-package.json5
@@ -0,0 +1,12 @@
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "in_app_purchase_ohos": "file:../har/in_app_purchase_ohos.har",
+ "integration_test": "file:../har/integration_test.har"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..8bc48be8773196f34cccb15cf517f87f5c6b94d2
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,24 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
+import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
+
+export default class EntryAbility extends FlutterAbility {
+ configureFlutterEngine(flutterEngine: FlutterEngine) {
+ super.configureFlutterEngine(flutterEngine)
+ GeneratedPluginRegistrant.registerWith(flutterEngine)
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/pages/Index.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..1125f9fdd95f4310a182c1c9e3680f37f73686c9
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import common from '@ohos.app.ability.common';
+import { FlutterPage } from '@ohos/flutter_ohos'
+
+let storage = LocalStorage.getShared()
+const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'
+
+@Entry(storage)
+@Component
+struct Index {
+ private context = getContext(this) as common.UIAbilityContext
+ @LocalStorageLink('viewId') viewId: string = "";
+
+ build() {
+ Column() {
+ FlutterPage({ viewId: this.viewId })
+ }
+ }
+
+ onBackPress(): boolean {
+ this.context.eventHub.emit(EVENT_BACK_PRESS)
+ return true
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/module.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..7bbf78b18f39991b1404061c7437538c7d532bb7
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/module.json5
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "requestPermissions": [
+ {"name" : "ohos.permission.INTERNET"},
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/color.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..67e0f4ff4ac762d1714f6e215c6636a4ad3d620e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/media/icon.png b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/media/icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/profile/main_pages.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/en_US/element/string.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/en_US/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..67e0f4ff4ac762d1714f6e215c6636a4ad3d620e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/en_US/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/zh_CN/element/string.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/zh_CN/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..601e2b5a1c273aa04920b126e3ab715a4450e58f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/main/resources/zh_CN/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "模块描述"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..25d4c71ff3cd584f5d64f6f8c0ac864928c234c4
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', function () {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(function () {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ })
+ beforeEach(function () {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ })
+ afterEach(function () {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ })
+ afterAll(function () {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ })
+ it('assertContain',0, function () {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
+ let a = 'abc'
+ let b = 'b'
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b)
+ expect(a).assertEqual(a)
+ })
+ })
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/List.test.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f4140030e65d20df6af30a6bf51e464dea8f8aa6
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import abilityTest from './Ability.test'
+
+export default function testsuite() {
+ abilityTest()
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..4ca645e6013cfce8e7dbb728313cb8840c4da660
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import hilog from '@ohos.hilog';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+import window from '@ohos.window';
+
+export default class TestAbility extends UIAbility {
+ onCreate(want, launchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? '');
+ var abilityDelegator: any
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var abilityDelegatorArguments: any
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
+ windowStage.loadContent('testability/pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
+ JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
+ }
+
+ onForeground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
+ }
+
+ onBackground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..cef0447cd2f137ef82d223ead2e156808878ab90
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+
+@Entry
+@Component
+struct Index {
+ aboutToAppear() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
+ }
+ @State message: string = 'Hello World'
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(50)
+ .fontWeight(FontWeight.Bold)
+ Button() {
+ Text('next page')
+ .fontSize(20)
+ .fontWeight(FontWeight.Bold)
+ }.type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .backgroundColor('#0D9FFB')
+ .width('35%')
+ .height('5%')
+ .onClick(()=>{
+ })
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+ }
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1def08f2e9dcbfa3454a07b7a3b82b173bb90d02
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import TestRunner from '@ohos.application.testRunner';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+
+var abilityDelegator = undefined
+var abilityDelegatorArguments = undefined
+
+async function onAbilityCreateCallback() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
+}
+
+async function addAbilityMonitorCallback(err: any) {
+ hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
+}
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
+ }
+
+ async onRun() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'
+ let lMonitor = {
+ abilityName: testAbilityName,
+ onAbilityCreate: onAbilityCreateCallback,
+ };
+ abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
+ var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName
+ var debug = abilityDelegatorArguments.parameters['-D']
+ if (debug == 'true')
+ {
+ cmd += ' -D'
+ }
+ hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd);
+ abilityDelegator.executeShellCommand(cmd,
+ (err: any, d: any) => {
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? '');
+ })
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/module.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..fab77ce2e0c61e3ad010bab5b27ccbd15f9a8c96
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/module.json5
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "description": "$string:module_test_desc",
+ "mainElement": "TestAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:test_pages",
+ "abilities": [
+ {
+ "name": "TestAbility",
+ "srcEntry": "./ets/testability/TestAbility.ets",
+ "description": "$string:TestAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:TestAbility_label",
+ "exported": true,
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "skills": [
+ {
+ "actions": [
+ "action.system.home"
+ ],
+ "entities": [
+ "entity.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/color.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/media/icon.png b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/media/icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "testability/pages/Index"
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/hvigor/hvigor-config.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..541ba35711b75986f9295410ee38fdb8f2572878
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/hvigor/hvigor-config.json5
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/hvigorfile.ts b/packages/in_app_purchase/in_app_purchase/example/ohos/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8f2d2aafe6d6a3a71a9944ebd0c91fbc308ac9d1
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/ohos/oh-package.json5 b/packages/in_app_purchase/in_app_purchase/example/ohos/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e955b929b0dc04a27550d0a075407cf140f19b78
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase/example/ohos/oh-package.json5
@@ -0,0 +1,21 @@
+{
+ "modelVersion": "5.0.0",
+ "name": "example",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har"
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.6"
+ },
+ "overrides": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har",
+ "in_app_purchase_ohos": "file:./har/in_app_purchase_ohos.har",
+ "integration_test": "file:./har/integration_test.har",
+ "@ohos/flutter_module": "file:./entry"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
index fcb72375f256b699aff61e72b010ceff9a533945..edc13ff9b20771e6df001ef96ed9b61710b6f71a 100644
--- a/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase/example/pubspec.yaml
@@ -18,7 +18,14 @@ dependencies:
path: ../
in_app_purchase_android: ^0.3.0
in_app_purchase_storekit: ^0.3.4
- shared_preferences: ^2.0.0
+ shared_preferences:
+ git:
+ url: https://gitee.com/openharmony-sig/flutter_packages.git
+ path: packages/shared_preferences/shared_preferences
+
+dependency_overrides:
+ in_app_purchase_ohos:
+ path: ../../in_app_purchase_ohos
dev_dependencies:
flutter_test:
diff --git a/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart b/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
index 64e0095dcbb7c47bd95769627a3491390e8366ae..2bd431449f717ada1a9b69a08a956285f18bff81 100644
--- a/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
+++ b/packages/in_app_purchase/in_app_purchase/lib/in_app_purchase.dart
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';
+import 'package:in_app_purchase_ohos/in_app_purchase_ohos.dart';
export 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart'
show
@@ -37,6 +38,8 @@ class InAppPurchase implements InAppPurchasePlatformAdditionProvider {
} else if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
InAppPurchaseStoreKitPlatform.registerPlatform();
+ } else if (defaultTargetPlatform == TargetPlatform.ohos) {
+ InAppPurchaseOhosPlatform.registerPlatform();
}
_instance = InAppPurchase._();
@@ -195,7 +198,7 @@ class InAppPurchase implements InAppPurchasePlatformAdditionProvider {
/// Restored purchases are delivered through the [purchaseStream] with a
/// status of [PurchaseStatus.restored]. You should listen for these purchases,
/// validate their receipts, deliver the content and mark the purchase complete
- /// by calling the [finishPurchase] method for each purchase.
+ /// by calling the [completePurchase] method for each purchase.
///
/// This does not return consumed products. If you want to restore unused
/// consumable products, you need to persist consumable product information
diff --git a/packages/in_app_purchase/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/in_app_purchase/pubspec.yaml
index ba95a32125a59e60f5e5ba15b104bb96977669ad..2c30df6651ddd137ef8d4f43052ff0b9a35f628e 100644
--- a/packages/in_app_purchase/in_app_purchase/pubspec.yaml
+++ b/packages/in_app_purchase/in_app_purchase/pubspec.yaml
@@ -2,7 +2,7 @@ name: in_app_purchase
description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
-version: 3.1.10
+version: 3.1.11
environment:
sdk: ">=2.19.0 <4.0.0"
@@ -13,6 +13,8 @@ flutter:
platforms:
android:
default_package: in_app_purchase_android
+ ohos:
+ default_package: in_app_purchase_ohos
ios:
default_package: in_app_purchase_storekit
macos:
@@ -22,6 +24,8 @@ dependencies:
flutter:
sdk: flutter
in_app_purchase_android: ^0.3.0
+ in_app_purchase_ohos:
+ path: ../in_app_purchase_ohos/
in_app_purchase_platform_interface: ^1.0.0
in_app_purchase_storekit: ^0.3.4
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/AUTHORS b/packages/in_app_purchase/in_app_purchase_ohos/AUTHORS
new file mode 100644
index 0000000000000000000000000000000000000000..78f9e5ad9f6b842b45e9fd070a44e042d6c7b6a9
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/AUTHORS
@@ -0,0 +1,67 @@
+# Below is a list of people and organizations that have contributed
+# to the Flutter project. Names should be added to the list like so:
+#
+# Name/Organization
+
+Google Inc.
+The Chromium Authors
+German Saprykin
+Benjamin Sauer
+larsenthomasj@gmail.com
+Ali Bitek
+Pol Batlló
+Anatoly Pulyaevskiy
+Hayden Flinner
+Stefano Rodriguez
+Salvatore Giordano
+Brian Armstrong
+Paul DeMarco
+Fabricio Nogueira
+Simon Lightfoot
+Ashton Thomas
+Thomas Danner
+Diego Velásquez
+Hajime Nakamura
+Tuyển Vũ Xuân
+Miguel Ruivo
+Sarthak Verma
+Mike Diarmid
+Invertase
+Elliot Hesp
+Vince Varga
+Aawaz Gyawali
+EUI Limited
+Katarina Sheremet
+Thomas Stockx
+Sarbagya Dhaubanjar
+Ozkan Eksi
+Rishab Nayak
+ko2ic
+Jonathan Younger
+Jose Sanchez
+Debkanchan Samadder
+Audrius Karosevicius
+Lukasz Piliszczuk
+SoundReply Solutions GmbH
+Rafal Wachol
+Pau Picas
+Christian Weder
+Alexandru Tuca
+Christian Weder
+Rhodes Davis Jr.
+Luigi Agosti
+Quentin Le Guennec
+Koushik Ravikumar
+Nissim Dsilva
+Giancarlo Rocha
+Ryo Miyake
+Théo Champion
+Kazuki Yamaguchi
+Eitan Schwartz
+Chris Rutkowski
+Juan Alvarez
+Aleksandr Yurkovskiy
+Anton Borries
+Alex Li
+Rahul Raj <64.rahulraj@gmail.com>
+Maurits van Beusekom
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_ohos/CHANGELOG.md
new file mode 100644
index 0000000000000000000000000000000000000000..4fac17c4689aeb69433e4c406db2da67aa1fa4b3
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/CHANGELOG.md
@@ -0,0 +1,3 @@
+## 0.1.0
+
+* Initial open-source release.
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/LICENSE b/packages/in_app_purchase/in_app_purchase_ohos/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..c6823b81eb845db89cee59cbbc7ee0b0b63d86ec
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/LICENSE
@@ -0,0 +1,25 @@
+Copyright 2013 The Flutter Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/README.md b/packages/in_app_purchase/in_app_purchase_ohos/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..971c114cbbe8c3e920073cd76066f81ef545796a
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/README.md
@@ -0,0 +1,24 @@
+# in\_app\_purchase\_ohos
+
+The Ohos implementation of [`in_app_purchase`][1].
+
+## Usage
+
+This package is [endorsed][2], which means you can simply use `in_app_purchase`
+normally. This package will be automatically included in your app when you do,
+so you do not need to add it to your `pubspec.yaml`.
+
+## Contributing
+
+This plugin utilizes
+[json_serializable](https://pub.dev/packages/json_serializable) for the
+numerous data structures communicated between the underlying platform layers and Dart. After
+modifying any of the serialized data structures, regenerate the serializers by executing
+`flutter pub run build_runner build --delete-conflicting-outputs`.
+`flutter pub run build_runner watch --delete-conflicting-outputs` will supervise the filesystem for changes.
+
+If you are interested in contributing to the plugin, please consult our
+[contribution guidelines](https://github.com/flutter/plugins/blob/main/CONTRIBUTING.md).
+
+[1]: https://pub.dev/packages/in_app_purchase
+[2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/build.yaml b/packages/in_app_purchase/in_app_purchase_ohos/build.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..651a557fc1ca5de4484891911e24fd8c0e7addf4
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/build.yaml
@@ -0,0 +1,8 @@
+# See https://pub.dev/packages/build_config
+targets:
+ $default:
+ builders:
+ json_serializable:
+ options:
+ any_map: true
+ create_to_json: false
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/README.md b/packages/in_app_purchase/in_app_purchase_ohos/example/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..96b8bb17dbff8e7acd9a1dd59c65ff40b96e1228
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/README.md
@@ -0,0 +1,9 @@
+# Platform Implementation Test App
+
+This is a test app for manual testing and automated integration testing
+of this platform implementation. It is not intended to demonstrate actual use of
+this package, since the intent is that plugin clients use the app-facing
+package.
+
+Unless you are making changes to this implementation package, this example is
+very unlikely to be relevant.
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/in_app_purchase_ohos/example/integration_test/in_app_purchase_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..28f99f748b4d199067672c3ffa2be0a32fcf979c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/integration_test/in_app_purchase_test.dart
@@ -0,0 +1,20 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:in_app_purchase_ohos/in_app_purchase_ohos.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+import 'package:integration_test/integration_test.dart';
+
+void main() {
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+ testWidgets('Can create InAppPurchaseStoreKit instance',
+ (WidgetTester tester) async {
+ InAppPurchaseOhosPlatform.registerPlatform();
+ final InAppPurchasePlatform androidPlatform =
+ InAppPurchasePlatform.instance;
+ expect(androidPlatform, isNotNull);
+ });
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/lib/consumable_store.dart b/packages/in_app_purchase/in_app_purchase_ohos/example/lib/consumable_store.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f8791d3b18c0524be8ec89cf02705cea880dd904
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/lib/consumable_store.dart
@@ -0,0 +1,52 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'package:shared_preferences/shared_preferences.dart';
+
+// ignore: avoid_classes_with_only_static_members
+/// A store of consumable items.
+///
+/// This is a development prototype that stores consumables in the shared
+/// preferences. Do not use this in real world apps.
+class ConsumableStore {
+ static const String _kPrefKey = 'consumables';
+ static Future _writes = Future.value();
+
+ /// Adds a consumable with ID `id` to the store.
+ ///
+ /// The consumable is only added after the returned Future is complete.
+ static Future save(String id) {
+ _writes = _writes.then((void _) => _doSave(id));
+ return _writes;
+ }
+
+ /// Consumes a consumable with ID `id` from the store.
+ ///
+ /// The consumable was only consumed after the returned Future is complete.
+ static Future consume(String id) {
+ _writes = _writes.then((void _) => _doConsume(id));
+ return _writes;
+ }
+
+ /// Returns the list of consumables from the store.
+ static Future> load() async {
+ return (await SharedPreferences.getInstance()).getStringList(_kPrefKey) ??
+ [];
+ }
+
+ static Future _doSave(String id) async {
+ final List cached = await load();
+ final SharedPreferences prefs = await SharedPreferences.getInstance();
+ cached.add(id);
+ await prefs.setStringList(_kPrefKey, cached);
+ }
+
+ static Future _doConsume(String id) async {
+ final List cached = await load();
+ final SharedPreferences prefs = await SharedPreferences.getInstance();
+ cached.remove(id);
+ await prefs.setStringList(_kPrefKey, cached);
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/lib/main.dart b/packages/in_app_purchase/in_app_purchase_ohos/example/lib/main.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d79a39189da8652f6e066a3efba0958f63cae015
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/lib/main.dart
@@ -0,0 +1,414 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+import 'package:in_app_purchase_ohos/in_app_purchase_ohos.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+import 'consumable_store.dart';
+
+void main() {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ // When using the Ohos plugin directly it is mandatory to register
+ // the plugin as default instance as part of initializing the app.
+ InAppPurchaseOhosPlatform.registerPlatform();
+
+ runApp(_MyApp());
+}
+
+const String _kConsumableId = 'consumable';
+const String _kUpgradeId = 'upgrade';
+const String _kSilverSubscriptionId = 'subscription_silver';
+const String _kGoldSubscriptionId = 'subscription_gold';
+const List _kProductIds = [
+ _kConsumableId,
+ _kUpgradeId,
+ _kSilverSubscriptionId,
+ _kGoldSubscriptionId,
+];
+
+class _MyApp extends StatefulWidget {
+ @override
+ State<_MyApp> createState() => _MyAppState();
+}
+
+class _MyAppState extends State<_MyApp> {
+ final InAppPurchaseOhosPlatform _iapStoreKitPlatform =
+ InAppPurchasePlatform.instance as InAppPurchaseOhosPlatform;
+ late StreamSubscription> _subscription;
+ List _notFoundIds = [];
+ List _products = [];
+ List _purchases = [];
+ List _consumables = [];
+ bool _isAvailable = false;
+ bool _purchasePending = false;
+ bool _loading = true;
+ String? _queryProductError;
+
+ @override
+ void initState() {
+ final Stream> purchaseUpdated =
+ _iapStoreKitPlatform.purchaseStream;
+ _subscription =
+ purchaseUpdated.listen((List purchaseDetailsList) {
+ _listenToPurchaseUpdated(purchaseDetailsList);
+ }, onDone: () {
+ _subscription.cancel();
+ }, onError: (Object error) {
+ // handle error here.
+ });
+
+ initStoreInfo();
+ super.initState();
+ }
+
+ Future initStoreInfo() async {
+ final bool isAvailable = await _iapStoreKitPlatform.isAvailable();
+ if (!isAvailable) {
+ setState(() {
+ _isAvailable = isAvailable;
+ _products = [];
+ _purchases = [];
+ _notFoundIds = [];
+ _consumables = [];
+ _purchasePending = false;
+ _loading = false;
+ });
+ return;
+ }
+ final ProductDetailsResponse productDetailResponse =
+ await _iapStoreKitPlatform.queryProductDetails(_kProductIds.toSet());
+ if (productDetailResponse.error != null) {
+ setState(() {
+ _queryProductError = productDetailResponse.error!.message;
+ _isAvailable = isAvailable;
+ _products = productDetailResponse.productDetails;
+ _purchases = [];
+ _notFoundIds = productDetailResponse.notFoundIDs;
+ _consumables = [];
+ _purchasePending = false;
+ _loading = false;
+ });
+ return;
+ }
+
+ if (productDetailResponse.productDetails.isEmpty) {
+ setState(() {
+ _queryProductError = null;
+ _isAvailable = isAvailable;
+ _products = productDetailResponse.productDetails;
+ _purchases = [];
+ _notFoundIds = productDetailResponse.notFoundIDs;
+ _consumables = [];
+ _purchasePending = false;
+ _loading = false;
+ });
+ return;
+ }
+
+ final List consumables = await ConsumableStore.load();
+ setState(() {
+ _isAvailable = isAvailable;
+ _products = productDetailResponse.productDetails;
+ _notFoundIds = productDetailResponse.notFoundIDs;
+ _consumables = consumables;
+ _purchasePending = false;
+ _loading = false;
+ });
+ }
+
+ @override
+ void dispose() {
+ _subscription.cancel();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final List stack = [];
+ if (_queryProductError == null) {
+ stack.add(
+ ListView(
+ children: [
+ _buildConnectionCheckTile(),
+ _buildProductList(),
+ _buildConsumableBox(),
+ // _buildRestoreButton(),
+ ],
+ ),
+ );
+ } else {
+ stack.add(Center(
+ child: Text(_queryProductError!),
+ ));
+ }
+ if (_purchasePending) {
+ stack.add(
+ // const Stack(
+ Stack(
+ children: [
+ Opacity(
+ opacity: 0.3,
+ child: ModalBarrier(dismissible: false, color: Colors.grey),
+ ),
+ Center(
+ child: CircularProgressIndicator(),
+ ),
+ ],
+ ),
+ );
+ }
+
+ return MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ title: const Text('IAP Example'),
+ ),
+ body: Stack(
+ children: stack,
+ ),
+ ),
+ );
+ }
+
+ Card _buildConnectionCheckTile() {
+ if (_loading) {
+ return const Card(child: ListTile(title: Text('Trying to connect...')));
+ }
+ final Widget storeHeader = ListTile(
+ leading: Icon(_isAvailable ? Icons.check : Icons.block,
+ color: _isAvailable
+ ? Colors.green
+ : ThemeData.light().colorScheme.error),
+ title:
+ Text('The store is ${_isAvailable ? 'available' : 'unavailable'}.'),
+ );
+ final List children = [storeHeader];
+
+ if (!_isAvailable) {
+ children.addAll([
+ const Divider(),
+ ListTile(
+ title: Text('Not connected',
+ style: TextStyle(color: ThemeData.light().colorScheme.error)),
+ subtitle: const Text(
+ 'Unable to connect to the payments processor. Has this app been configured correctly? See the example README for instructions.'),
+ ),
+ ]);
+ }
+ return Card(child: Column(children: children));
+ }
+
+ Card _buildProductList() {
+ if (_loading) {
+ return const Card(
+ child: ListTile(
+ leading: CircularProgressIndicator(),
+ title: Text('Fetching products...')));
+ }
+ if (!_isAvailable) {
+ return const Card();
+ }
+ const ListTile productHeader = ListTile(title: Text('Products for Sale'));
+ final List productList = [];
+ if (_notFoundIds.isNotEmpty) {
+ productList.add(ListTile(
+ title: Text('[${_notFoundIds.join(", ")}] not found',
+ style: TextStyle(color: ThemeData.light().colorScheme.error)),
+ subtitle: const Text(
+ 'This app needs special configuration to run. Please see example/README.md for instructions.')));
+ }
+
+ // This loading previous purchases code is just a demo. Please do not use this as it is.
+ // In your app you should always verify the purchase data using the `verificationData` inside the [PurchaseDetails] object before trusting it.
+ // We recommend that you use your own server to verify the purchase data.
+ final Map purchases =
+ Map.fromEntries(
+ _purchases.map((PurchaseDetails purchase) {
+ if (purchase.pendingCompletePurchase) {
+ _iapStoreKitPlatform.completePurchase(purchase);
+ }
+ return MapEntry(purchase.productID, purchase);
+ }));
+ productList.addAll(_products.map(
+ (ProductDetails productDetails) {
+ final PurchaseDetails? previousPurchase = purchases[productDetails.id];
+ return ListTile(
+ title: Text(
+ productDetails.title,
+ ),
+ subtitle: Text(
+ productDetails.description,
+ ),
+ trailing: previousPurchase != null
+ ? SizedBox.shrink()
+ : TextButton(
+ style: TextButton.styleFrom(
+ backgroundColor: Colors.green[800],
+ foregroundColor: Colors.white,
+ ),
+ onPressed: () {
+ final PurchaseParam purchaseParam = PurchaseParam(
+ productDetails: productDetails,
+ );
+ if (productDetails.id == _kConsumableId) {
+ _iapStoreKitPlatform.buyConsumable(
+ purchaseParam: purchaseParam);
+ } else {
+ _iapStoreKitPlatform.buyNonConsumable(
+ purchaseParam: purchaseParam);
+ }
+ },
+ child: Text(productDetails.price),
+ ));
+ },
+ ));
+
+ return Card(
+ child: Column(
+ children: [productHeader, const Divider()] + productList));
+ }
+
+ Card _buildConsumableBox() {
+ if (_loading) {
+ return const Card(
+ child: ListTile(
+ leading: CircularProgressIndicator(),
+ title: Text('Fetching consumables...')));
+ }
+ if (!_isAvailable || _notFoundIds.contains(_kConsumableId)) {
+ return const Card();
+ }
+ const ListTile consumableHeader =
+ ListTile(title: Text('Purchased consumables'));
+ final List tokens = _consumables.map((String id) {
+ return GridTile(
+ child: IconButton(
+ icon: const Icon(
+ Icons.stars,
+ size: 42.0,
+ color: Colors.orange,
+ ),
+ splashColor: Colors.yellowAccent,
+ onPressed: () => consume(id),
+ ),
+ );
+ }).toList();
+ return Card(
+ child: Column(children: [
+ consumableHeader,
+ const Divider(),
+ GridView.count(
+ crossAxisCount: 5,
+ shrinkWrap: true,
+ padding: const EdgeInsets.all(16.0),
+ children: tokens,
+ )
+ ]));
+ }
+
+ Widget _buildRestoreButton() {
+ if (_loading) {
+ return Container();
+ }
+
+ return Padding(
+ padding: const EdgeInsets.all(4.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ TextButton(
+ style: TextButton.styleFrom(
+ backgroundColor: Theme.of(context).colorScheme.primary,
+ foregroundColor: Colors.white,
+ ),
+ onPressed: () => _iapStoreKitPlatform.restorePurchases(),
+ child: const Text('Restore purchases'),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Future consume(String id) async {
+ await ConsumableStore.consume(id);
+ final List consumables = await ConsumableStore.load();
+ setState(() {
+ _consumables = consumables;
+ });
+ }
+
+ void showPendingUI() {
+ setState(() {
+ _purchasePending = true;
+ });
+ }
+
+ Future deliverProduct(PurchaseDetails purchaseDetails) async {
+ // IMPORTANT!! Always verify purchase details before delivering the product.
+ if (purchaseDetails.productID == _kConsumableId) {
+ await ConsumableStore.save(purchaseDetails.purchaseID!);
+ final List consumables = await ConsumableStore.load();
+ setState(() {
+ _purchasePending = false;
+ _consumables = consumables;
+ });
+ } else {
+ setState(() {
+ _purchases.add(purchaseDetails);
+ _purchasePending = false;
+ });
+ }
+ }
+
+ void handleError(IAPError error) {
+ setState(() {
+ _purchasePending = false;
+ });
+ }
+
+ Future _verifyPurchase(PurchaseDetails purchaseDetails) {
+ // IMPORTANT!! Always verify a purchase before delivering the product.
+ // For the purpose of an example, we directly return true.
+ return Future.value(true);
+ }
+
+ void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
+ // handle invalid purchase here if _verifyPurchase` failed.
+ }
+
+ void _listenToPurchaseUpdated(List purchaseDetailsList) {
+ purchaseDetailsList.forEach(_handleReportedPurchaseState);
+ }
+
+ Future _handleReportedPurchaseState(
+ PurchaseDetails purchaseDetails) async {
+ print('InAppPurchasePlugin purchaseDetails.status =$purchaseDetails');
+ if (purchaseDetails.status == PurchaseStatus.pending) {
+ showPendingUI();
+ } else {
+ if (purchaseDetails.status == PurchaseStatus.error) {
+ handleError(purchaseDetails.error!);
+ } else if (purchaseDetails.status == PurchaseStatus.purchased ||
+ purchaseDetails.status == PurchaseStatus.restored) {
+ final bool valid = await _verifyPurchase(purchaseDetails);
+ if (valid) {
+ await deliverProduct(purchaseDetails);
+ } else {
+ _handleInvalidPurchase(purchaseDetails);
+ return;
+ }
+ }else if(purchaseDetails.status == PurchaseStatus.canceled){
+
+ }
+
+ if (purchaseDetails.pendingCompletePurchase) {
+ await _iapStoreKitPlatform.completePurchase(purchaseDetails);
+ }
+ }
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/.gitignore b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..6ca13b3170eec5dd5ac5ad7f1c4dd0118845f473
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/.gitignore
@@ -0,0 +1,19 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+*.har
+**/BuildProfile.ets
+**/oh-package-lock.json5
+
+**/src/main/resources/rawfile/flutter_assets/
+**/libs/arm64-v8a/libapp.so
+**/libs/arm64-v8a/libflutter.so
+**/libs/arm64-v8a/libvmservice_snapshot.so
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/app.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..a13c8bfdc16a34697a1ce5c7dc8e207275149473
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.example.in_app_purchase_ohos",
+ "vendor": "example",
+ "versionCode": 1000000,
+ "versionName": "1.0.0",
+ "icon": "$media:app_icon",
+ "label": "$string:app_name"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..810f4a362c1d177309eec4f2efe5cac2f4558c28
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "example"
+ }
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/media/app_icon.png b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/media/app_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/AppScope/resources/base/media/app_icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/build-profile.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..1d12140d202702d7c73d64f1b291fe5c45a660ce
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/build-profile.json5
@@ -0,0 +1,27 @@
+{
+ "app": {
+ "signingConfigs": [],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.0.0(12)",
+ "runtimeOS": "HarmonyOS"
+ }
+ ]
+ },
+ "modules": [
+ {
+ "name": "entry",
+ "srcPath": "./entry",
+ "targets": [
+ {
+ "name": "default",
+ "applyToProducts": [
+ "default"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/.gitignore b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2795a1c5b1fe53659dd1b71d90ba0592eaf7e043
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/.gitignore
@@ -0,0 +1,7 @@
+
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/build-profile.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..633d360fbc91a3186a23b66ab71b27e5618944cb
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/build-profile.json5
@@ -0,0 +1,29 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "apiType": 'stageMode',
+ "buildOption": {
+ },
+ "targets": [
+ {
+ "name": "default",
+ "runtimeOS": "HarmonyOS"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/hvigorfile.ts b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5bda56eeac3f79703639db986e2faaa433b0e48c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/hvigorfile.ts
@@ -0,0 +1,17 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
+export { hapTasks } from '@ohos/hvigor-ohos-plugin';
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/oh-package.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..0dabd8f8158dd0c7ef1dd55fc8361f234192f9d0
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/oh-package.json5
@@ -0,0 +1,13 @@
+{
+ "name": "entry",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "in_app_purchase_ohos": "file:../har/in_app_purchase_ohos.har",
+ "integration_test": "file:../har/integration_test.har",
+ "shared_preferences_ohos": "file:../har/shared_preferences_ohos.har"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b5888ed9002dd328f9abd3141ee3e63e88b40d0f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,24 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
+import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
+
+export default class EntryAbility extends FlutterAbility {
+ configureFlutterEngine(flutterEngine: FlutterEngine) {
+ super.configureFlutterEngine(flutterEngine)
+ GeneratedPluginRegistrant.registerWith(flutterEngine)
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/pages/Index.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..5d9647743f4651f3dab7aa3076ed0707b207b436
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import common from '@ohos.app.ability.common';
+import { FlutterPage } from '@ohos/flutter_ohos'
+
+let storage = LocalStorage.getShared()
+const EVENT_BACK_PRESS = 'EVENT_BACK_PRESS'
+
+@Entry(storage)
+@Component
+struct Index {
+ private context = getContext(this) as common.UIAbilityContext
+ @LocalStorageLink('viewId') viewId: string = "";
+
+ build() {
+ Column() {
+ FlutterPage({ viewId: this.viewId })
+ }
+ }
+
+ onBackPress(): boolean {
+ this.context.eventHub.emit(EVENT_BACK_PRESS)
+ return true
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0569b3bbcb6759d2988addd26cbefff06fd96c4a
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/ets/plugins/GeneratedPluginRegistrant.ets
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { FlutterEngine, Log } from '@ohos/flutter_ohos';
+import InAppPurchasePlugin from 'in_app_purchase_ohos';
+import IntegrationTestPlugin from 'integration_test';
+import SharedPreferencesPlugin from 'shared_preferences_ohos';
+
+/**
+ * Generated file. Do not edit.
+ * This file is generated by the Flutter tool based on the
+ * plugins that support the Ohos platform.
+ */
+
+const TAG = "GeneratedPluginRegistrant";
+
+export class GeneratedPluginRegistrant {
+
+ static registerWith(flutterEngine: FlutterEngine) {
+ try {
+ flutterEngine.getPlugins()?.add(new InAppPurchasePlugin());
+ flutterEngine.getPlugins()?.add(new IntegrationTestPlugin());
+ flutterEngine.getPlugins()?.add(new SharedPreferencesPlugin());
+ } catch (e) {
+ Log.e(
+ TAG,
+ "Tried to register plugins with FlutterEngine ("
+ + flutterEngine
+ + ") failed.");
+ Log.e(TAG, "Received exception while registering", e);
+ }
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/module.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..7bbf78b18f39991b1404061c7437538c7d532bb7
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/module.json5
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "abilities": [
+ {
+ "name": "EntryAbility",
+ "srcEntry": "./ets/entryability/EntryAbility.ets",
+ "description": "$string:EntryAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:EntryAbility_label",
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "exported": true,
+ "skills": [
+ {
+ "entities": [
+ "entity.system.home"
+ ],
+ "actions": [
+ "action.system.home"
+ ]
+ }
+ ]
+ }
+ ],
+ "requestPermissions": [
+ {"name" : "ohos.permission.INTERNET"},
+ ]
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/color.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..67e0f4ff4ac762d1714f6e215c6636a4ad3d620e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/media/icon.png b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/media/icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/base/profile/main_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "pages/Index"
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..67e0f4ff4ac762d1714f6e215c6636a4ad3d620e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/en_US/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..601e2b5a1c273aa04920b126e3ab715a4450e58f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/main/resources/zh_CN/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "模块描述"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..bdb2d4b3479e7c4b3d4ffb539abc734470c57f32
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/Ability.test.ets
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
+
+export default function abilityTest() {
+ describe('ActsAbilityTest', function () {
+ // Defines a test suite. Two parameters are supported: test suite name and test suite function.
+ beforeAll(function () {
+ // Presets an action, which is performed only once before all test cases of the test suite start.
+ // This API supports only one parameter: preset action function.
+ })
+ beforeEach(function () {
+ // Presets an action, which is performed before each unit test case starts.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: preset action function.
+ })
+ afterEach(function () {
+ // Presets a clear action, which is performed after each unit test case ends.
+ // The number of execution times is the same as the number of test cases defined by **it**.
+ // This API supports only one parameter: clear action function.
+ })
+ afterAll(function () {
+ // Presets a clear action, which is performed after all test cases of the test suite end.
+ // This API supports only one parameter: clear action function.
+ })
+ it('assertContain',0, function () {
+ // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
+ hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
+ let a = 'abc'
+ let b = 'b'
+ // Defines a variety of assertion methods, which are used to declare expected boolean conditions.
+ expect(a).assertContain(b)
+ expect(a).assertEqual(a)
+ })
+ })
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/List.test.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
new file mode 100644
index 0000000000000000000000000000000000000000..5ed99383f79bb67de7472f356de5b0421fa26e71
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/test/List.test.ets
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import abilityTest from './Ability.test'
+
+export default function testsuite() {
+ abilityTest()
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..465211ee2e66f8b16d8c28881acc0f534df700e5
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/TestAbility.ets
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import UIAbility from '@ohos.app.ability.UIAbility';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+import hilog from '@ohos.hilog';
+import { Hypium } from '@ohos/hypium';
+import testsuite from '../test/List.test';
+import window from '@ohos.window';
+
+export default class TestAbility extends UIAbility {
+ onCreate(want, launchParam) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
+ hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? '');
+ var abilityDelegator: any
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var abilityDelegatorArguments: any
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
+ Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
+ }
+
+ onDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
+ }
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
+ windowStage.loadContent('testability/pages/Index', (err, data) => {
+ if (err.code) {
+ hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
+ return;
+ }
+ hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
+ JSON.stringify(data) ?? '');
+ });
+ }
+
+ onWindowStageDestroy() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
+ }
+
+ onForeground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
+ }
+
+ onBackground() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..bdf1e5f905bcacd6a73af7709c41d4a79d41b170
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testability/pages/Index.ets
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+
+@Entry
+@Component
+struct Index {
+ aboutToAppear() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
+ }
+ @State message: string = 'Hello World'
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ .fontSize(50)
+ .fontWeight(FontWeight.Bold)
+ Button() {
+ Text('next page')
+ .fontSize(20)
+ .fontWeight(FontWeight.Bold)
+ }.type(ButtonType.Capsule)
+ .margin({
+ top: 20
+ })
+ .backgroundColor('#0D9FFB')
+ .width('35%')
+ .height('5%')
+ .onClick(()=>{
+ })
+ }
+ .width('100%')
+ }
+ .height('100%')
+ }
+ }
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
new file mode 100644
index 0000000000000000000000000000000000000000..58d9c312f08e7c9ac01e4d6f2d0a33ddc6188ed9
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/ets/testrunner/OpenHarmonyTestRunner.ts
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import hilog from '@ohos.hilog';
+import TestRunner from '@ohos.application.testRunner';
+import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
+
+var abilityDelegator = undefined
+var abilityDelegatorArguments = undefined
+
+async function onAbilityCreateCallback() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
+}
+
+async function addAbilityMonitorCallback(err: any) {
+ hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
+}
+
+export default class OpenHarmonyTestRunner implements TestRunner {
+ constructor() {
+ }
+
+ onPrepare() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
+ }
+
+ async onRun() {
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
+ abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
+ abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
+ var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'
+ let lMonitor = {
+ abilityName: testAbilityName,
+ onAbilityCreate: onAbilityCreateCallback,
+ };
+ abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
+ var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName
+ var debug = abilityDelegatorArguments.parameters['-D']
+ if (debug == 'true')
+ {
+ cmd += ' -D'
+ }
+ hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd);
+ abilityDelegator.executeShellCommand(cmd,
+ (err: any, d: any) => {
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? '');
+ hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? '');
+ })
+ hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/module.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..fab77ce2e0c61e3ad010bab5b27ccbd15f9a8c96
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/module.json5
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "module": {
+ "name": "entry_test",
+ "type": "feature",
+ "description": "$string:module_test_desc",
+ "mainElement": "TestAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:test_pages",
+ "abilities": [
+ {
+ "name": "TestAbility",
+ "srcEntry": "./ets/testability/TestAbility.ets",
+ "description": "$string:TestAbility_desc",
+ "icon": "$media:icon",
+ "label": "$string:TestAbility_label",
+ "exported": true,
+ "startWindowIcon": "$media:icon",
+ "startWindowBackground": "$color:start_window_background",
+ "skills": [
+ {
+ "actions": [
+ "action.system.home"
+ ],
+ "entities": [
+ "entity.system.home"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json
new file mode 100644
index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/color.json
@@ -0,0 +1,8 @@
+{
+ "color": [
+ {
+ "name": "start_window_background",
+ "value": "#FFFFFF"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json
new file mode 100644
index 0000000000000000000000000000000000000000..65d8fa5a7cf54aa3943dcd0214f58d1771bc1f6c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/element/string.json
@@ -0,0 +1,16 @@
+{
+ "string": [
+ {
+ "name": "module_test_desc",
+ "value": "test ability description"
+ },
+ {
+ "name": "TestAbility_desc",
+ "value": "the test ability"
+ },
+ {
+ "name": "TestAbility_label",
+ "value": "test label"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c
Binary files /dev/null and b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/media/icon.png differ
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
new file mode 100644
index 0000000000000000000000000000000000000000..b7e7343cacb32ce982a45e76daad86e435e054fe
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/entry/src/ohosTest/resources/base/profile/test_pages.json
@@ -0,0 +1,5 @@
+{
+ "src": [
+ "testability/pages/Index"
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigor/hvigor-config.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigor/hvigor-config.json5
new file mode 100644
index 0000000000000000000000000000000000000000..541ba35711b75986f9295410ee38fdb8f2572878
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigor/hvigor-config.json5
@@ -0,0 +1,20 @@
+/*
+* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+{
+ "modelVersion": "5.0.0",
+ "dependencies": {
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigorfile.ts b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..38626e385a5b47dd3cba0e1e83c614f091b7cc9e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { appTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/oh-package.json5 b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..81da8c679151fb90deafcfea3617d7463ac9a0d1
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/ohos/oh-package.json5
@@ -0,0 +1,22 @@
+{
+ "modelVersion": "5.0.0",
+ "name": "example",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "",
+ "author": "",
+ "license": "",
+ "dependencies": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har"
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.6"
+ },
+ "overrides": {
+ "@ohos/flutter_ohos": "file:./har/flutter.har",
+ "in_app_purchase_ohos": "file:./har/in_app_purchase_ohos.har",
+ "shared_preferences_ohos": "file:./har/shared_preferences_ohos.har",
+ "integration_test": "file:./har/integration_test.har",
+ "@ohos/flutter_module": "file:./entry"
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/example/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_ohos/example/pubspec.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..657c9d1cab93a692ef1e97588d82bcee34eb5bc6
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/example/pubspec.yaml
@@ -0,0 +1,33 @@
+name: in_app_purchase_ohos_example
+description: Demonstrates how to use the in_app_purchase_ohos plugin.
+publish_to: none
+
+environment:
+ sdk: ">=2.19.0 <4.0.0"
+ flutter: ">=3.7.0"
+
+dependencies:
+ flutter:
+ sdk: flutter
+ in_app_purchase_ohos:
+ # When depending on this package from a real application you should use:
+ # in_app_purchase_ohos: ^x.y.z
+ # See https://dart.dev/tools/pub/dependencies#version-constraints
+ # The example app is bundled with the plugin so we use a path dependency on
+ # the parent directory to use the current plugin's version.
+ path: ../
+ in_app_purchase_platform_interface: ^1.0.0
+ shared_preferences:
+ git:
+ url: https://gitee.com/openharmony-sig/flutter_packages.git
+ path: packages/shared_preferences/shared_preferences
+
+dev_dependencies:
+ # build_runner: ^2.4.5
+ flutter_test:
+ sdk: flutter
+ integration_test:
+ sdk: flutter
+
+flutter:
+ uses-material-design: true
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/iap_kit_wrappers.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/iap_kit_wrappers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..eade8d181a423271bdd006693187b3bceb3e3266
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/iap_kit_wrappers.dart
@@ -0,0 +1,9 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export 'src/iap_kit_wrappers/ik_payment_queue_wrapper.dart';
+export 'src/iap_kit_wrappers/ik_payment_transaction_wrappers.dart';
+export 'src/iap_kit_wrappers/ik_product_wrapper.dart';
+export 'src/iap_kit_wrappers/ik_receipt_manager.dart';
+export 'src/iap_kit_wrappers/ik_request_maker.dart';
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/in_app_purchase_ohos.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/in_app_purchase_ohos.dart
new file mode 100644
index 0000000000000000000000000000000000000000..bee9e1c9af5a87b59b3b834cd115de3db5cbff3e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/in_app_purchase_ohos.dart
@@ -0,0 +1,7 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export 'src/in_app_purchase_ohos_platform.dart';
+export 'src/in_app_purchase_ohos_platform_addition.dart';
+export 'src/types/types.dart';
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/channel.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/channel.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c8b9d647a28c30b58e641ab229c21982c8f789e1
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/channel.dart
@@ -0,0 +1,9 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/services.dart';
+
+/// Method channel for the plugin's platform<-->Dart calls.
+const MethodChannel channel =
+ MethodChannel('plugins.flutter.io/in_app_purchase');
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/README.md b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8a99aab65991bcdb9538d628393657dc0c65bc62
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/README.md
@@ -0,0 +1,5 @@
+# iap_kit_wrappers
+
+This exposes Dart endpoints through to the
+IAP Kit APIs. It offers functionality
+as an alternative to [in_app_purchase](../in_app_purchase/README.md).
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.dart
new file mode 100644
index 0000000000000000000000000000000000000000..76e1932354e1e339d5d250164c32b481ce949ded
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.dart
@@ -0,0 +1,143 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../iap_kit_wrappers.dart';
+
+part 'enum_converters.g.dart';
+
+/// Serializer for [IKPaymentTransactionStateWrapper].
+///
+/// Use these in `@JsonSerializable()` classes by annotating them with
+/// `@IKTransactionStatusConverter()`.
+class IKTransactionStatusConverter
+ implements JsonConverter {
+ /// Default const constructor.
+ const IKTransactionStatusConverter();
+
+ @override
+ IKPaymentTransactionStateWrapper fromJson(int? json) {
+ if (json == null) {
+ return IKPaymentTransactionStateWrapper.unspecified;
+ }
+ return $enumDecode(
+ _$IKPaymentTransactionStateWrapperEnumMap
+ .cast(),
+ json);
+ }
+
+ /// Converts an [IKPaymentTransactionStateWrapper] to a [PurchaseStatus].
+ PurchaseStatus toPurchaseStatus(
+ IKPaymentTransactionStateWrapper object, IKError? error) {
+ print('MethodCallHandlerImpl toPurchaseStatus. $object');
+ switch (object) {
+ case IKPaymentTransactionStateWrapper.purchasing:
+ case IKPaymentTransactionStateWrapper.deferred:
+ return PurchaseStatus.pending;
+ case IKPaymentTransactionStateWrapper.purchased:
+ return PurchaseStatus.purchased;
+ case IKPaymentTransactionStateWrapper.restored:
+ return PurchaseStatus.restored;
+ case IKPaymentTransactionStateWrapper.failed:
+ // According to the Apple documentation the error code "2" indicates
+ // the user cancelled the payment (IKErrorPaymentCancelled) and error
+ // code "15" indicates the cancellation of the overlay (IKErrorOverlayCancelled).
+ if (error != null && (error.code == 2 || error.code == 15)) {
+ return PurchaseStatus.canceled;
+ }
+ return PurchaseStatus.error;
+ case IKPaymentTransactionStateWrapper.unspecified:
+ return PurchaseStatus.error;
+ }
+ }
+
+ @override
+ int toJson(IKPaymentTransactionStateWrapper object) =>
+ _$IKPaymentTransactionStateWrapperEnumMap[object]!;
+}
+
+/// Serializer for [IKSubscriptionPeriodUnit].
+///
+/// Use these in `@JsonSerializable()` classes by annotating them with
+/// `@IKSubscriptionPeriodUnitConverter()`.
+class IKSubscriptionPeriodUnitConverter
+ implements JsonConverter {
+ /// Default const constructor.
+ const IKSubscriptionPeriodUnitConverter();
+
+ @override
+ IKSubscriptionPeriodUnit fromJson(int? json) {
+ if (json == null) {
+ return IKSubscriptionPeriodUnit.day;
+ }
+ return $enumDecode(
+ _$IKSubscriptionPeriodUnitEnumMap
+ .cast(),
+ json);
+ }
+
+ @override
+ int toJson(IKSubscriptionPeriodUnit object) =>
+ _$IKSubscriptionPeriodUnitEnumMap[object]!;
+}
+
+/// Serializer for [IKProductDiscountPaymentMode].
+///
+/// Use these in `@JsonSerializable()` classes by annotating them with
+/// `@IKProductDiscountPaymentModeConverter()`.
+class IKProductDiscountPaymentModeConverter
+ implements JsonConverter {
+ /// Default const constructor.
+ const IKProductDiscountPaymentModeConverter();
+
+ @override
+ IKProductDiscountPaymentMode fromJson(int? json) {
+ if (json == null) {
+ return IKProductDiscountPaymentMode.payAsYouGo;
+ }
+ return $enumDecode(
+ _$IKProductDiscountPaymentModeEnumMap
+ .cast(),
+ json);
+ }
+
+ @override
+ int toJson(IKProductDiscountPaymentMode object) =>
+ _$IKProductDiscountPaymentModeEnumMap[object]!;
+}
+
+// Define a class so we generate serializer helper methods for the enums
+// See https://github.com/google/json_serializable.dart/issues/778
+@JsonSerializable()
+class _SerializedEnums {
+ late IKPaymentTransactionStateWrapper response;
+ late IKSubscriptionPeriodUnit unit;
+ late IKProductDiscountPaymentMode discountPaymentMode;
+}
+
+/// Serializer for [IKProductDiscountType].
+///
+/// Use these in `@JsonSerializable()` classes by annotating them with
+/// `@IKProductDiscountTypeConverter()`.
+class IKProductDiscountTypeConverter
+ implements JsonConverter {
+ /// Default const constructor.
+ const IKProductDiscountTypeConverter();
+
+ @override
+ IKProductDiscountType fromJson(int? json) {
+ if (json == null) {
+ return IKProductDiscountType.introductory;
+ }
+ return $enumDecode(
+ _$IKProductDiscountTypeEnumMap.cast(),
+ json);
+ }
+
+ @override
+ int toJson(IKProductDiscountType object) =>
+ _$IKProductDiscountTypeEnumMap[object]!;
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.g.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.g.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1fd872ac6fc51499b191a0a4e1868f47569c55af
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/enum_converters.g.dart
@@ -0,0 +1,42 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'enum_converters.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+_SerializedEnums _$SerializedEnumsFromJson(Map json) => _SerializedEnums()
+ ..response =
+ $enumDecode(_$IKPaymentTransactionStateWrapperEnumMap, json['response'])
+ ..unit = $enumDecode(_$IKSubscriptionPeriodUnitEnumMap, json['unit'])
+ ..discountPaymentMode = $enumDecode(
+ _$IKProductDiscountPaymentModeEnumMap, json['discountPaymentMode']);
+
+const _$IKPaymentTransactionStateWrapperEnumMap = {
+ IKPaymentTransactionStateWrapper.purchasing: 0,
+ IKPaymentTransactionStateWrapper.purchased: 1,
+ IKPaymentTransactionStateWrapper.failed: 2,
+ IKPaymentTransactionStateWrapper.restored: 3,
+ IKPaymentTransactionStateWrapper.deferred: 4,
+ IKPaymentTransactionStateWrapper.unspecified: -1,
+};
+
+const _$IKSubscriptionPeriodUnitEnumMap = {
+ IKSubscriptionPeriodUnit.day: 0,
+ IKSubscriptionPeriodUnit.week: 1,
+ IKSubscriptionPeriodUnit.month: 2,
+ IKSubscriptionPeriodUnit.year: 3,
+};
+
+const _$IKProductDiscountPaymentModeEnumMap = {
+ IKProductDiscountPaymentMode.payAsYouGo: 0,
+ IKProductDiscountPaymentMode.payUpFront: 1,
+ IKProductDiscountPaymentMode.freeTrail: 2,
+ IKProductDiscountPaymentMode.unspecified: -1,
+};
+
+const _$IKProductDiscountTypeEnumMap = {
+ IKProductDiscountType.introductory: 0,
+ IKProductDiscountType.subscription: 1,
+};
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c4fdc94af11cc5d47573d11eabb84c4236ff0b41
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.dart
@@ -0,0 +1,264 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:collection/collection.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+import '../../iap_kit_wrappers.dart';
+import '../channel.dart';
+import '../in_app_purchase_ohos_platform.dart';
+
+part 'ik_payment_queue_wrapper.g.dart';
+
+class IKPaymentQueueWrapper {
+ /// Returns the default payment queue.
+ ///
+ /// We do not support instantiating a custom payment queue, hence the
+ /// singleton. However, you can override the observer.
+ factory IKPaymentQueueWrapper() {
+ return _singleton;
+ }
+
+ IKPaymentQueueWrapper._();
+
+ static final IKPaymentQueueWrapper _singleton = IKPaymentQueueWrapper._();
+
+ IKTransactionObserverWrapper? _observer;
+
+ Future> transactions() async {
+ return _getTransactionList((await channel
+ .invokeListMethod('iap#transactions'))!);
+ }
+
+ static Future queryEnvironmentStatus() async =>
+ (await channel.invokeMethod('iap#queryEnvironmentStatus')) ?? false;
+
+ void setTransactionObserver(IKTransactionObserverWrapper observer) {
+ _observer = observer;
+ channel.setMethodCallHandler(handleObserverCallbacks);
+ }
+
+ Future startObservingTransactionQueue() =>
+ channel.invokeMethod('iap#startObservingTransactionQueue');
+
+ Future stopObservingTransactionQueue() =>
+ channel.invokeMethod('iap#stopObservingTransactionQueue');
+
+ Future addPayment(IKPaymentWrapper payment) async {
+ assert(_observer != null,
+ '[in_app_purchase]: Trying to add a payment without an observer. One must be set using `IKPaymentQueueWrapper.setTransactionObserver` before the app launches.');
+ final Map requestMap = payment.toMap();
+ await channel.invokeMethod(
+ 'iap#createPurchase',
+ requestMap,
+ );
+ }
+
+ Future finishTransaction(
+ IKPaymentTransactionWrapper transaction) async {
+ final Map requestMap = transaction.toFinishMap();
+ await channel.invokeMethod(
+ 'iap#finishPurchase',
+ requestMap,
+ );
+ }
+
+ // 暂未实现
+ Future restoreTransactions({String? applicationUserName}) async {
+ await channel.invokeMethod(
+ 'iap#restoreTransactions', applicationUserName);
+ }
+
+ /// Triage a method channel call from the platform and triggers the correct observer method.
+ ///
+ /// This method is public for testing purposes only and should not be used
+ /// outside this class.
+ @visibleForTesting
+ Future handleObserverCallbacks(MethodCall call) async {
+ assert(_observer != null,
+ '[in_app_purchase]: (Fatal)The observer has not been set but we received a purchase transaction notification. Please ensure the observer has been set using `setTransactionObserver`. Make sure the observer is added right at the App Launch.');
+ print('MethodCallHandlerImpl handleObserverCallbacks : ' + call.method);
+ final IKTransactionObserverWrapper observer = _observer!;
+ switch (call.method) {
+ case 'updatedTransactions':
+ {
+ print('MethodCallHandlerImpl handleObserverCallbacks');
+ final List transactions =
+ _getTransactionList(call.arguments as List);
+ return Future(() {
+ observer.updatedTransactions(transactions: transactions);
+ });
+ }
+ case 'removedTransactions':
+ {
+ final List transactions =
+ _getTransactionList(call.arguments as List);
+ return Future(() {
+ observer.removedTransactions(transactions: transactions);
+ });
+ }
+ default:
+ break;
+ }
+ throw PlatformException(
+ code: 'no_such_callback',
+ message: 'Did not recognize the observer callback ${call.method}.');
+ }
+
+ // Get transaction wrapper object list from arguments.
+ List _getTransactionList(
+ List transactionsData) {
+ return transactionsData.map((dynamic map) {
+ return IKPaymentTransactionWrapper.fromJson(
+ Map.castFrom(
+ map as Map));
+ }).toList();
+ }
+}
+
+@immutable
+@JsonSerializable()
+class IKError {
+ /// Creates a new [IKError] object with the provided information.
+ const IKError(
+ {required this.code, required this.domain, required this.userInfo});
+
+ /// Constructs an instance of this from a key-value map of data.
+ ///
+ /// The map needs to have named string keys with values matching the names and
+ /// types of all of the members on this class. The `map` parameter must not be
+ /// null.
+ factory IKError.fromJson(Map map) {
+ return _$IKErrorFromJson(map);
+ }
+
+ /// Error code
+ @JsonKey(defaultValue: 0)
+ final int code;
+
+ /// Error
+ @JsonKey(defaultValue: '')
+ final String domain;
+
+ /// A map that contains more detailed information about the error.
+ @JsonKey(defaultValue: {})
+ final Map userInfo;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
+ return true;
+ }
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is IKError &&
+ other.code == code &&
+ other.domain == domain &&
+ const DeepCollectionEquality.unordered()
+ .equals(other.userInfo, userInfo);
+ }
+
+ @override
+ int get hashCode => Object.hash(
+ code,
+ domain,
+ userInfo,
+ );
+}
+
+/// Dart wrapper around IAP Kit
+/// [PurchaseParameter](https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/iap-iap-V5#section1340120344598).
+///
+/// Used as the parameter to initiate a payment. In general, a developer should
+/// not need to create the payment object explicitly; instead, use
+/// [IKPaymentQueueWrapper.addPayment] directly with a product identifier to
+/// initiate a payment.
+@immutable
+@JsonSerializable(createToJson: true)
+class IKPaymentWrapper {
+ /// Creates a new [IKPaymentWrapper] with the provided information.
+ const IKPaymentWrapper({
+ required this.productId,
+ this.productType,
+ this.developerPayload,
+ this.reservedInfo,
+ this.promotionalOfferId,
+ this.applicationUserName,
+ this.jwsRepresentation,
+ });
+
+ /// Constructs an instance of this from a key value map of data.
+ ///
+ /// The map needs to have named string keys with values matching the names and
+ /// types of all of the members on this class. The `map` parameter must not be
+ /// null.
+ factory IKPaymentWrapper.fromJson(Map map) {
+ return _$IKPaymentWrapperFromJson(map);
+ }
+
+ /// Creates a Map object describes the payment object.
+ Map toMap() {
+ return {
+ 'productId': productId,
+ 'productType': productType,
+ 'developerPayload': developerPayload,
+ 'reservedInfo': reservedInfo,
+ 'promotionalOfferId': promotionalOfferId,
+ 'applicationUserName': applicationUserName,
+ 'jwsRepresentation': jwsRepresentation,
+ };
+ }
+
+ /// 待支付的商品ID。商品ID来源于开发者在AppGallery Connect中配置商品信息时设置的“商品ID”,具体请参见配置商品信息。
+ final String productId;
+
+ /// 需要查询的商品类型
+ final ProductType? productType;
+
+ /// 商户侧保留信息
+ final String? developerPayload;
+
+ /// 要求JSON String格式,商户可以将额外需要传入的字段以key-value的形式设置在JSON String中,并通过该参数传入。
+ final String? reservedInfo;
+
+ /// 优惠ID。优惠ID来源于开发者在AppGallery Connect中配置商品信息时设置的促销优惠标识符,
+ /// 具体请参见设置促销价格。传递该字段且要生效,需传递jwsRepresentation字段包含促销优惠信息。
+ final String? promotionalOfferId;
+
+ /// 用户账户相关联的混淆字符串,唯一标识用户。传递优惠ID场景,可以传递该字段。
+ final String? applicationUserName;
+
+ /// 包含购买参数信息的JWS格式签名数据。购买参数,如促销优惠等。
+ final String? jwsRepresentation;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
+ return true;
+ }
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is IKPaymentWrapper &&
+ other.productId == productId &&
+ other.productType == productType &&
+ other.developerPayload == developerPayload &&
+ other.reservedInfo == reservedInfo &&
+ other.promotionalOfferId == promotionalOfferId &&
+ other.applicationUserName == applicationUserName &&
+ other.jwsRepresentation == jwsRepresentation;
+ }
+
+ @override
+ int get hashCode => Object.hash(productId, productType, developerPayload,
+ reservedInfo, promotionalOfferId);
+
+ @override
+ String toString() => _$IKPaymentWrapperToJson(this).toString();
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.g.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1cd277f1c9b10a2b83274e66cb45d73c0070c4b3
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_queue_wrapper.g.dart
@@ -0,0 +1,50 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'ik_payment_queue_wrapper.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+IKError _$IKErrorFromJson(Map json) => IKError(
+ code: json['code'] as int? ?? 0,
+ domain: json['domain'] as String? ?? '',
+ userInfo: (json['userInfo'] as Map?)?.map(
+ (k, e) => MapEntry(k as String, e),
+ ) ??
+ {},
+ );
+
+IKPaymentWrapper _$IKPaymentWrapperFromJson(Map json) => IKPaymentWrapper(
+ productId: json['productId'] as String? ?? '',
+ productType: _$IKProductTypeFromInt(json['productType'] as int? ?? 0),
+ developerPayload: json['developerPayload'] as String?,
+ reservedInfo: json['reservedInfo'] as String?,
+ promotionalOfferId: json['promotionalOfferId'] as String?,
+ applicationUserName: json['applicationUserName'] as String?,
+ jwsRepresentation: json['jwsRepresentation'] as String?,
+ );
+
+Map _$IKPaymentWrapperToJson(IKPaymentWrapper instance) =>
+ {
+ 'productId': instance.productId,
+ 'productType': instance.productType,
+ 'developerPayload': instance.developerPayload,
+ 'reservedInfo': instance.reservedInfo,
+ 'promotionalOfferId': instance.promotionalOfferId,
+ 'applicationUserName': instance.applicationUserName,
+ 'jwsRepresentation': instance.jwsRepresentation,
+ };
+
+ProductType _$IKProductTypeFromInt(int type) {
+ switch (type) {
+ case 0:
+ return ProductType.CONSUMABLE;
+ case 1:
+ return ProductType.NONCONSUMABLE;
+ case 3:
+ return ProductType.AUTORENEWABLE;
+ default:
+ return ProductType.CONSUMABLE;
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..dc34cd9551f989eb46340f5a0137c113df7f6c92
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.dart
@@ -0,0 +1,172 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/foundation.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+import 'enum_converters.dart';
+import 'ik_payment_queue_wrapper.dart';
+import 'ik_product_wrapper.dart';
+
+part 'ik_payment_transaction_wrappers.g.dart';
+
+/// Callback handlers for transaction status changes.
+abstract class IKTransactionObserverWrapper {
+ /// Triggered when any transactions are updated.
+ void updatedTransactions(
+ {required List transactions});
+
+ /// Triggered when any transactions are removed from the payment queue.
+ void removedTransactions(
+ {required List transactions});
+}
+
+/// The state of a transaction.
+enum IKPaymentTransactionStateWrapper {
+ /// Indicates the transaction is being processed in App Store.
+ ///
+ /// You should update your UI to indicate that you are waiting for the
+ /// transaction to update to another state. Never complete a transaction that
+ /// is still in a purchasing state.
+ @JsonValue(0)
+ purchasing,
+
+ /// The user's payment has been succesfully processed.
+ ///
+ /// You should provide the user the content that they purchased.
+ @JsonValue(1)
+ purchased,
+
+ /// The transaction failed.
+ ///
+ /// Check the [IKPaymentTransactionWrapper.error] property from
+ /// [IKPaymentTransactionWrapper] for details.
+ @JsonValue(2)
+ failed,
+
+ /// This transaction is restoring content previously purchased by the user.
+ ///
+ /// The previous transaction information can be obtained in
+ /// [IKPaymentTransactionWrapper.originalTransaction] from
+ /// [IKPaymentTransactionWrapper].
+ @JsonValue(3)
+ restored,
+
+ /// The transaction is in the queue but pending external action. Wait for
+ /// another callback to get the final state.
+ ///
+ /// You should update your UI to indicate that you are waiting for the
+ /// transaction to update to another state.
+ @JsonValue(4)
+ deferred,
+
+ /// Indicates the transaction is in an unspecified state.
+ @JsonValue(-1)
+ unspecified,
+}
+
+/// Created when a payment is added to the [IKPaymentQueueWrapper].
+///
+/// Transactions are delivered to your app when a payment is finished
+/// processing. Completed transactions provide a receipt and a transaction
+/// identifier that the app can use to save a permanent record of the processed
+/// payment.
+@JsonSerializable(createToJson: true)
+@immutable
+class IKPaymentTransactionWrapper {
+ /// Creates a new [IKPaymentTransactionWrapper] with the provided information.
+ // TODO(stuartmorgan): Temporarily ignore const warning in other parts of the
+ // federated package, and remove this.
+ // ignore: prefer_const_constructors_in_immutables
+ IKPaymentTransactionWrapper({
+ required this.payment,
+ required this.transactionState,
+ this.originalTransaction,
+ this.transactionTimeStamp,
+ this.transactionIdentifier,
+ this.error,
+ });
+
+ /// Constructs an instance of this from a key value map of data.
+ ///
+ /// The map needs to have named string keys with values matching the names and
+ /// types of all of the members on this class. The `map` parameter must not be
+ /// null.
+ factory IKPaymentTransactionWrapper.fromJson(Map map) {
+ return _$IKPaymentTransactionWrapperFromJson(map);
+ }
+
+ /// Current transaction state.
+ @IKTransactionStatusConverter()
+ final IKPaymentTransactionStateWrapper transactionState;
+
+ /// The payment that has been created and added to the payment queue which
+ /// generated this transaction.
+ final IKPaymentWrapper payment;
+
+ /// The original Transaction.
+ ///
+ /// Only available if the [transactionState] is [SKPaymentTransactionStateWrapper.restored].
+ /// Otherwise the value is `null`.
+ ///
+ /// When the [transactionState]
+ /// is [IKPaymentTransactionStateWrapper.restored], the current transaction
+ /// object holds a new [transactionIdentifier].
+ final IKPaymentTransactionWrapper? originalTransaction;
+
+ /// The timestamp of the transaction.
+ ///
+ /// Seconds since epoch. It is only defined when the [transactionState] is
+ /// [IKPaymentTransactionStateWrapper.purchased] or
+ /// [IKPaymentTransactionStateWrapper.restored].
+ /// Otherwise, the value is `null`.
+ final double? transactionTimeStamp;
+
+ /// The unique string identifer of the transaction.
+ ///
+ /// It is only defined when the [transactionState] is
+ /// [IKPaymentTransactionStateWrapper.purchased] or
+ /// [IKPaymentTransactionStateWrapper.restored]. You may wish to record this
+ /// string as part of an audit trail for App Store purchases. The value of
+ /// this string corresponds to the same property in the receipt.
+ ///
+ /// The value is `null` if it is an unsuccessful transaction.
+ final String? transactionIdentifier;
+
+ /// The error object
+ ///
+ /// Only available if the [transactionState] is
+ /// [IKPaymentTransactionStateWrapper.failed].
+ final IKError? error;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
+ return true;
+ }
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is IKPaymentTransactionWrapper &&
+ other.payment == payment &&
+ other.transactionState == transactionState &&
+ other.originalTransaction == originalTransaction &&
+ other.transactionTimeStamp == transactionTimeStamp &&
+ other.transactionIdentifier == transactionIdentifier &&
+ other.error == error;
+ }
+
+ @override
+ int get hashCode => Object.hash(payment, transactionState,
+ originalTransaction, transactionTimeStamp, transactionIdentifier, error);
+
+ @override
+ String toString() => _$IKPaymentTransactionWrapperToJson(this).toString();
+
+ /// The payload that is used to finish this transaction.
+ Map toFinishMap() => {
+ 'transactionIdentifier': transactionIdentifier,
+ 'productIdentifier': payment.productId,
+ };
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.g.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.g.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9a51a4267cada34f1173bf2cab2411e6fbf5fd6a
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_payment_transaction_wrappers.g.dart
@@ -0,0 +1,36 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'ik_payment_transaction_wrappers.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+IKPaymentTransactionWrapper _$IKPaymentTransactionWrapperFromJson(Map json) =>
+ IKPaymentTransactionWrapper(
+ payment: IKPaymentWrapper.fromJson(
+ Map.from(json['payment'] as Map)),
+ transactionState: const IKTransactionStatusConverter()
+ .fromJson(json['transactionState'] as int?),
+ originalTransaction: json['originalTransaction'] == null
+ ? null
+ : IKPaymentTransactionWrapper.fromJson(
+ Map.from(json['originalTransaction'] as Map)),
+ transactionTimeStamp: (json['transactionTimeStamp'] as num?)?.toDouble(),
+ transactionIdentifier: json['transactionIdentifier'] as String?,
+ error: json['error'] == null
+ ? null
+ : IKError.fromJson(Map.from(json['error'] as Map)),
+ );
+
+Map _$IKPaymentTransactionWrapperToJson(
+ IKPaymentTransactionWrapper instance) =>
+ {
+ 'transactionState': const IKTransactionStatusConverter()
+ .toJson(instance.transactionState),
+ 'payment': instance.payment,
+ 'originalTransaction': instance.originalTransaction,
+ 'transactionTimeStamp': instance.transactionTimeStamp,
+ 'transactionIdentifier': instance.transactionIdentifier,
+ 'error': instance.error,
+ };
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.dart
new file mode 100644
index 0000000000000000000000000000000000000000..057e60ac240a82cfa5087c397a93a5c61f773cfb
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.dart
@@ -0,0 +1,279 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:collection/collection.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:json_annotation/json_annotation.dart';
+import 'enum_converters.dart';
+
+// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the
+// below generated file. Run `flutter packages pub run build_runner watch` to
+// rebuild and watch for further changes.
+part 'ik_product_wrapper.g.dart';
+
+/// Represents the response object returned by [IKRequestMaker.startProductRequest].
+/// Contains information about a list of products and a list of invalid product identifiers.
+@JsonSerializable()
+@immutable
+class IKProductResponseWrapper {
+ /// Creates an [IKProductResponseWrapper] with the given product details.
+ // TODO(stuartmorgan): Temporarily ignore const warning in other parts of the
+ // federated package, and remove this.
+ // ignore: prefer_const_constructors_in_immutables
+ IKProductResponseWrapper(
+ {required this.products, required this.invalidProductIdentifiers});
+
+ /// Constructing an instance from a map from the Objective-C layer.
+ ///
+ /// This method should only be used with `map` values returned by [IKRequestMaker.startProductRequest].
+ factory IKProductResponseWrapper.fromJson(Map map) {
+ var maptt = _$SkProductResponseWrapperFromJson(map);
+ return _$SkProductResponseWrapperFromJson(map);
+ }
+
+ /// Stores all matching successfully found products.
+ ///
+ /// One product in this list matches one valid product identifier passed to the [IKRequestMaker.startProductRequest].
+ /// Will be empty if the [IKRequestMaker.startProductRequest] method does not pass any correct product identifier.
+ @JsonKey(defaultValue: [])
+ final List products;
+
+ /// Stores product identifiers in the `productIdentifiers` from [IKRequestMaker.startProductRequest] that are not recognized by the AppGallery.
+ /// Will be empty if all the product identifiers are valid.
+ @JsonKey(defaultValue: [])
+ final List invalidProductIdentifiers;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
+ return true;
+ }
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is IKProductResponseWrapper &&
+ const DeepCollectionEquality().equals(other.products, products) &&
+ const DeepCollectionEquality()
+ .equals(other.invalidProductIdentifiers, invalidProductIdentifiers);
+ }
+
+ @override
+ int get hashCode => Object.hash(products, invalidProductIdentifiers);
+}
+
+/// Used as a property in the [IKProductSubscriptionPeriodWrapper]. Minimum is a day and maximum is a year.
+// The values of the enum options are matching the [IKProductPeriodUnit]'s values. Should there be an update or addition
+// in the [IKProductPeriodUnit], this need to be updated to match.
+enum IKSubscriptionPeriodUnit {
+ /// An interval lasting one day.
+ @JsonValue(0)
+ day,
+
+ /// An interval lasting one month.
+ @JsonValue(1)
+
+ /// An interval lasting one week.
+ week,
+ @JsonValue(2)
+
+ /// An interval lasting one month.
+ month,
+
+ /// An interval lasting one year.
+ @JsonValue(3)
+ year,
+}
+
+/// A period is defined by a [numberOfUnits] and a [unit], e.g for a 3 months period [numberOfUnits] is 3 and [unit] is a month.
+/// It is used as a property in [IKProductDiscountWrapper] and [IKProductWrapper].
+@JsonSerializable()
+@immutable
+class IKProductSubscriptionPeriodWrapper {
+ /// Creates an [IKProductSubscriptionPeriodWrapper] for a `numberOfUnits`x`unit` period.
+ // TODO(stuartmorgan): Temporarily ignore const warning in other parts of the
+ // federated package, and remove this.
+ // ignore: prefer_const_constructors_in_immutables
+ IKProductSubscriptionPeriodWrapper(
+ {required this.numberOfUnits, required this.unit});
+
+ /// Constructing an instance from a map from the Objective-C layer.
+ ///
+ /// This method should only be used with `map` values returned by [IKProductDiscountWrapper.fromJson] or [IKProductWrapper.fromJson].
+ factory IKProductSubscriptionPeriodWrapper.fromJson(
+ Map? map) {
+ if (map == null) {
+ return IKProductSubscriptionPeriodWrapper(
+ numberOfUnits: 0, unit: IKSubscriptionPeriodUnit.day);
+ }
+ return _$IKProductSubscriptionPeriodWrapperFromJson(map);
+ }
+
+ /// The number of [unit] units in this period.
+ ///
+ /// Must be greater than 0 if the object is valid.
+ @JsonKey(defaultValue: 0)
+ final int numberOfUnits;
+
+ /// The time unit used to specify the length of this period.
+ @IKSubscriptionPeriodUnitConverter()
+ final IKSubscriptionPeriodUnit unit;
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) {
+ return true;
+ }
+ if (other.runtimeType != runtimeType) {
+ return false;
+ }
+ return other is IKProductSubscriptionPeriodWrapper &&
+ other.numberOfUnits == numberOfUnits &&
+ other.unit == unit;
+ }
+
+ @override
+ int get hashCode => Object.hash(numberOfUnits, unit);
+}
+
+/// This is used as a property in the [IKProductDiscountWrapper].
+// The values of the enum options are matching the [IKProductDiscountPaymentMode]'s values. Should there be an update or addition
+// in the [IKProductDiscountPaymentMode], this need to be updated to match.
+enum IKProductDiscountPaymentMode {
+ /// Allows user to pay the discounted price at each payment period.
+ @JsonValue(0)
+ payAsYouGo,
+
+ /// Allows user to pay the discounted price upfront and receive the product for the rest of time that was paid for.
+ @JsonValue(1)
+ payUpFront,
+
+ /// User pays nothing during the discounted period.
+ @JsonValue(2)
+ freeTrail,
+
+ /// Unspecified mode.
+ @JsonValue(-1)
+ unspecified,
+}
+
+
+/// This is used as a property in the [IKProductDiscountWrapper].
+/// The values of the enum options are matching the [IKProductDiscountType]'s
+/// values.
+///
+/// Values representing the types of discount offers an app can present.
+enum IKProductDiscountType {
+ /// A constant indicating the discount type is an introductory offer.
+ @JsonValue(0)
+ introductory,
+
+ /// A constant indicating the discount type is a promotional offer.
+ @JsonValue(1)
+ subscription,
+}
+
+/// Dart wrapper around IAP Kit [Product](https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/iap-iap-V5#section346874219313).
+///
+/// A list of [IKProductWrapper] is returned in the [IKRequestMaker.startProductRequest] method, and
+/// should be stored for use when making a payment.
+@JsonSerializable()
+@immutable
+class IKProductWrapper {
+ /// Creates an [IKProductWrapper] with the given product details.
+ // TODO(stuartmorgan): Temporarily ignore const warning in other parts of the
+ // federated package, and remove this.
+ // ignore: prefer_const_constructors_in_immutables
+ IKProductWrapper({
+ required this.id,
+ required this.type,
+ required this.name,
+ required this.description,
+ required this.localPrice,
+ required this.microPrice,
+ required this.originalLocalPrice,
+ required this.originalMicroPrice,
+ required this.currency,
+ this.status,
+ // this.subscriptionInfo,
+ // this.promotionalOffers,
+ this.jsonRepresentation,
+ });
+
+ /// Constructing an instance from a map from the ets layer.
+ ///
+ /// This method should only be used with `map` values returned by [IKProductResponseWrapper.fromJson].
+ factory IKProductWrapper.fromJson(Map map) {
+ return _$IKProductWrapperFromJson(map);
+ }
+
+ /// 商品ID
+ final String id;
+
+ /// 商品类型
+ final ProductType type;
+
+ /// 商品名称,为配置商品信息时配置的名称。用于显示在应用内支付收银台
+ final String name;
+
+ /// 商品描述,即配置商品信息时配置的描述信息
+ final String description;
+
+ /// 商品的展示价格,包含商品币种和价格,格式为“币种+商品价格”,例如 EUR 0.15。部分国家/地区会返回“货币符号+商品价格”,例如中国大陆返回“¥0.15”。此价格含税。可选。
+ final String localPrice;
+
+ /// 商品实际价格乘以1,000,000后的微单位价格。例如某个商品实际价格是1.99美元,则该商品对应的微单位价格为:1.99*1000000=1990000。
+ final int microPrice;
+
+ /// 商品的原价,包含商品币种和价格,格式为“币种+商品价格”,例如 EUR 0.15。部分国家/地区会返回“货币符号+商品价格”,例如中国大陆返回“¥0.15”。此价格含税。
+ final String originalLocalPrice;
+
+ /// 商品原价的微单位价格。商品原价乘以1,000,000后的微单位价格。例如某个商品原价是1.99美元,则该商品对应的微单位价格为:1.99*1000000=1990000。
+ final int originalMicroPrice;
+
+ /// 用于支付该商品的币种,必须符合ISO 4217标准,例如USD、CNY、MYR。
+ final String currency;
+
+ /// 商品状态
+ final ProductStatus? status;
+
+ /// 自动续期订阅商品相关的信息。可选。
+ // final SubscriptionInfo? subscriptionInfo;
+
+ /// 订阅商品支持的优惠信息列表
+ // final PromotionalOffer[]? promotionalOffers;
+
+ /// 商品详细信息的原始JSON字符串
+ final String? jsonRepresentation;
+}
+
+/// 商品状态枚举
+enum ProductType {
+ /// 消耗型商品
+ @JsonValue(0)
+ CONSUMABLE,
+
+ /// 非消耗型商品
+ @JsonValue(1)
+ NONCONSUMABLE,
+
+ /// 自动续期订阅商品
+ @JsonValue(3)
+ AUTORENEWABLE,
+}
+
+/// 商品状态枚举
+enum ProductStatus {
+ /// 有效状态。
+ @JsonValue(0)
+ VALID,
+
+ /// 取消状态,即删除。此状态的商品不可续订,也不可订阅。
+ @JsonValue(1)
+ CANCELED,
+
+ /// 下线状态,不能订阅,但老用户仍可续订。
+ @JsonValue(3)
+ OFFLINE,
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.g.dart
new file mode 100644
index 0000000000000000000000000000000000000000..072612e1c4be955a94c1a46b9a5073fc24575d9f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_product_wrapper.g.dart
@@ -0,0 +1,69 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'ik_product_wrapper.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+IKProductResponseWrapper _$SkProductResponseWrapperFromJson(Map json) =>
+ IKProductResponseWrapper(
+ products: (json['products'] as List?)
+ ?.map((e) => IKProductWrapper.fromJson(
+ Map.from(e as Map)))
+ .toList() ??
+ [],
+ invalidProductIdentifiers:
+ (json['invalidProductIdentifiers'] as List?)
+ ?.map((e) => e as String)
+ .toList() ??
+ [],
+ );
+
+IKProductSubscriptionPeriodWrapper _$IKProductSubscriptionPeriodWrapperFromJson(
+ Map json) =>
+ IKProductSubscriptionPeriodWrapper(
+ numberOfUnits: json['numberOfUnits'] as int? ?? 0,
+ unit: const IKSubscriptionPeriodUnitConverter()
+ .fromJson(json['unit'] as int?),
+ );
+
+IKProductWrapper _$IKProductWrapperFromJson(Map json) => IKProductWrapper(
+ id: json['id'] as String? ?? '',
+ type: _$IKProductTypeFromInt(json['type'] as int? ?? 0),
+ name: json['name'] as String? ?? '',
+ description: json['description'] as String? ?? '',
+ localPrice: json['localPrice'] as String? ?? '',
+ microPrice: json['microPrice'] as int? ?? 0,
+ originalLocalPrice: json['originalLocalPrice'] as String? ?? '',
+ originalMicroPrice: json['originalMicroPrice'] as int? ?? 0,
+ currency: json['currency'] as String? ?? '',
+ status: _$IKProductStatusFromInt(json['status'] as int? ?? 0),
+ jsonRepresentation: json['jsonRepresentation'] as String?,
+ );
+
+ProductType _$IKProductTypeFromInt(int type) {
+ switch (type) {
+ case 0:
+ return ProductType.CONSUMABLE;
+ case 1:
+ return ProductType.NONCONSUMABLE;
+ case 3:
+ return ProductType.AUTORENEWABLE;
+ default:
+ return ProductType.CONSUMABLE;
+ }
+}
+
+ProductStatus _$IKProductStatusFromInt(int type) {
+ switch (type) {
+ case 0:
+ return ProductStatus.VALID;
+ case 1:
+ return ProductStatus.CANCELED;
+ case 3:
+ return ProductStatus.OFFLINE;
+ default:
+ return ProductStatus.VALID;
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_receipt_manager.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_receipt_manager.dart
new file mode 100644
index 0000000000000000000000000000000000000000..68feb9e103623e4e13d1ad42b35b99c07651126c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_receipt_manager.dart
@@ -0,0 +1,18 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import '../channel.dart';
+
+// ignore: avoid_classes_with_only_static_members
+/// This class contains static methods to manage StoreKit receipts.
+class IKReceiptManager {
+ /// Retrieve the receipt data from your application's main bundle.
+ static Future retrieveReceiptData() async {
+ return (await channel.invokeMethod(
+ 'iap#retrieveReceiptData')) ??
+ '';
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_request_maker.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_request_maker.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0eebfe8362bb047f46293948d574d3bccc96e71b
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/iap_kit_wrappers/ik_request_maker.dart
@@ -0,0 +1,46 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+
+import '../channel.dart';
+import 'ik_product_wrapper.dart';
+
+/// A request maker that handles all the requests made by IKRequest subclasses.
+class IKRequestMaker {
+ /// Fetches product information for a list of given product identifiers.
+ ///
+ /// The `productIdentifiers` should contain legitimate product identifiers that you declared for the products in the iTunes Connect. Invalid identifiers
+ /// will be stored and returned in [SkProductResponseWrapper.invalidProductIdentifiers]. Duplicate values in `productIdentifiers` will be omitted.
+ /// If `productIdentifiers` is null, an `storekit_invalid_argument` error will be returned. If `productIdentifiers` is empty, a [SkProductResponseWrapper]
+ /// will still be returned with [SkProductResponseWrapper.products] being null.
+ ///
+ /// [SkProductResponseWrapper] is returned if there is no error during the request.
+ /// A [PlatformException] is thrown if the platform code making the request fails.
+ Future startProductRequest(
+ List productIdentifiers) async {
+ final Map? productResponseMap =
+ await channel.invokeMapMethod(
+ 'iap#queryProducts',
+ productIdentifiers,
+ );
+ if (productResponseMap == null) {
+ throw PlatformException(
+ code: 'storekit_no_response',
+ message: 'StoreKit: Failed to get response from platform.',
+ );
+ }
+ return IKProductResponseWrapper.fromJson(productResponseMap);
+ }
+
+ Future startRefreshReceiptRequest(
+ {Map? receiptProperties}) {
+ return channel.invokeMethod(
+ 'iap#refreshReceipt',
+ receiptProperties,
+ );
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2fa17d603b1554f8269d990456733526a027e372
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform.dart
@@ -0,0 +1,219 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/services.dart';
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+import '../iap_kit_wrappers.dart';
+import '../in_app_purchase_ohos.dart';
+
+/// [IAPError.code] code for failed purchases.
+const String kPurchaseErrorCode = 'purchase_error';
+
+/// Indicates store front is AppGallery.
+const String kIAPSource = 'app_gallery';
+
+/// An [InAppPurchasePlatform] that wraps IAP Kit.
+///
+/// This translates various `IAP Kit` calls and responses into the
+/// generic plugin API.
+class InAppPurchaseOhosPlatform extends InAppPurchasePlatform {
+ /// Creates an [InAppPurchaseOhosPlatform] object.
+ ///
+ /// This constructor should only be used for testing, for any other purpose
+ /// get the connection from the [instance] getter.
+ @visibleForTesting
+ InAppPurchaseOhosPlatform();
+
+ static late IKPaymentQueueWrapper _skPaymentQueueWrapper;
+ static late _TransactionObserver _observer;
+
+ @override
+ Stream> get purchaseStream =>
+ _observer.purchaseUpdatedController.stream;
+
+ /// Callback handler for transaction status changes.
+ @visibleForTesting
+ static IKTransactionObserverWrapper get observer => _observer;
+
+ /// Registers this class as the default instance of [InAppPurchasePlatform].
+ static void registerPlatform() {
+ // Register the [InAppPurchaseOhosPlatformAddition] containing
+ // IapKit-specific functionality.
+ InAppPurchasePlatformAddition.instance =
+ InAppPurchaseOhosPlatformAddition();
+
+ // Register the platform-specific implementation of the idiomatic
+ // InAppPurchase API.
+ InAppPurchasePlatform.instance = InAppPurchaseOhosPlatform();
+
+ _skPaymentQueueWrapper = IKPaymentQueueWrapper();
+
+ // Create a purchaseUpdatedController and notify the native side when to
+ // start of stop sending updates.
+ final StreamController> updateController =
+ StreamController>.broadcast(
+ onListen: () => _skPaymentQueueWrapper.startObservingTransactionQueue(),
+ onCancel: () => _skPaymentQueueWrapper.stopObservingTransactionQueue(),
+ );
+ _observer = _TransactionObserver(updateController);
+ _skPaymentQueueWrapper.setTransactionObserver(observer);
+ }
+
+ @override
+ Future isAvailable() => IKPaymentQueueWrapper.queryEnvironmentStatus();
+
+ @override
+ Future buyNonConsumable({required PurchaseParam purchaseParam}) async {
+ await _skPaymentQueueWrapper.addPayment(
+ IKPaymentWrapper(productId: purchaseParam.productDetails.id));
+ return true; // There's no error feedback from ohos here to return.
+ }
+
+ @override
+ Future buyConsumable(
+ {required PurchaseParam purchaseParam, bool autoConsume = true}) {
+ assert(autoConsume == true, 'On ohos, we should always auto consume');
+ return buyNonConsumable(purchaseParam: purchaseParam);
+ }
+
+ @override
+ Future completePurchase(PurchaseDetails purchase) {
+ assert(
+ purchase is AppGalleryPurchaseDetails,
+ 'On ohos, the `purchase` should always be of type `AppGalleryPurchaseDetails`.',
+ );
+
+ return _skPaymentQueueWrapper.finishTransaction(
+ (purchase as AppGalleryPurchaseDetails).ikPaymentTransaction,
+ );
+ }
+
+ @override
+ Future restorePurchases({String? applicationUserName}) async {
+ return _observer
+ .restoreTransactions(
+ queue: _skPaymentQueueWrapper,
+ applicationUserName: applicationUserName)
+ .whenComplete(() => _observer.cleanUpRestoredTransactions());
+ }
+
+ /// Query the product detail list.
+ ///
+ /// This method only returns [ProductDetailsResponse].
+ /// To get detailed Store Kit product list, use [SkProductResponseWrapper.startProductRequest]
+ /// to get the [IKProductResponseWrapper].
+ @override
+ Future queryProductDetails(
+ Set identifiers) async {
+ final IKRequestMaker requestMaker = IKRequestMaker();
+ IKProductResponseWrapper response;
+ PlatformException? exception;
+ try {
+ response = await requestMaker.startProductRequest(identifiers.toList());
+ print('InAppPurchasePlugin productDetailResponse response');
+ } on PlatformException catch (e) {
+ exception = e;
+ response = IKProductResponseWrapper(
+ products: const [],
+ invalidProductIdentifiers: identifiers.toList());
+ }
+ List productDetails =
+ [];
+ productDetails = response.products
+ .map((IKProductWrapper productWrapper) =>
+ AppGalleryProductDetails.fromIKProduct(productWrapper))
+ .toList();
+ List invalidIdentifiers = response.invalidProductIdentifiers;
+ if (productDetails.isEmpty) {
+ invalidIdentifiers = identifiers.toList();
+ }
+ final ProductDetailsResponse productDetailsResponse =
+ ProductDetailsResponse(
+ productDetails: productDetails,
+ notFoundIDs: invalidIdentifiers,
+ error: exception == null
+ ? null
+ : IAPError(
+ source: kIAPSource,
+ code: exception.code,
+ message: exception.message ?? '',
+ details: exception.details),
+ );
+ return productDetailsResponse;
+ }
+}
+
+enum _TransactionRestoreState {
+ notRunning,
+ waitingForTransactions,
+ receivedTransaction,
+}
+
+class _TransactionObserver implements IKTransactionObserverWrapper {
+ _TransactionObserver(this.purchaseUpdatedController);
+
+ final StreamController> purchaseUpdatedController;
+
+ Completer? _restoreCompleter;
+ late String _receiptData;
+ _TransactionRestoreState _transactionRestoreState =
+ _TransactionRestoreState.notRunning;
+
+ Future restoreTransactions({
+ required IKPaymentQueueWrapper queue,
+ String? applicationUserName,
+ }) {
+ _transactionRestoreState = _TransactionRestoreState.waitingForTransactions;
+ _restoreCompleter = Completer();
+ queue.restoreTransactions(applicationUserName: applicationUserName);
+ return _restoreCompleter!.future;
+ }
+
+ void cleanUpRestoredTransactions() {
+ _restoreCompleter = null;
+ }
+
+ @override
+ void updatedTransactions(
+ {required List transactions}) {
+ _handleTransationUpdates(transactions);
+ }
+
+ @override
+ void removedTransactions(
+ {required List transactions}) {}
+
+ Future getReceiptData() async {
+ try {
+ _receiptData = await IKReceiptManager.retrieveReceiptData();
+ } catch (e) {
+ _receiptData = '';
+ }
+ return _receiptData;
+ }
+
+ Future _handleTransationUpdates(
+ List transactions) async {
+ print('MethodCallHandlerImpl _handleTransationUpdates ');
+ if (_transactionRestoreState ==
+ _TransactionRestoreState.waitingForTransactions &&
+ transactions.any((IKPaymentTransactionWrapper transaction) =>
+ transaction.transactionState ==
+ IKPaymentTransactionStateWrapper.restored)) {
+ _transactionRestoreState = _TransactionRestoreState.receivedTransaction;
+ }
+
+ final String receiptData = await getReceiptData();
+ final List purchases = transactions
+ .map((IKPaymentTransactionWrapper transaction) =>
+ AppGalleryPurchaseDetails.fromIKTransaction(
+ transaction, receiptData))
+ .toList();
+ purchaseUpdatedController.add(purchases);
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform_addition.dart
new file mode 100644
index 0000000000000000000000000000000000000000..88a0325358931fc30d47a145df61ea217e637344
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/in_app_purchase_ohos_platform_addition.dart
@@ -0,0 +1,33 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+import '../iap_kit_wrappers.dart';
+import '../in_app_purchase_ohos.dart';
+
+/// Contains InApp Purchase features that are only available on ohos.
+class InAppPurchaseOhosPlatformAddition
+ extends InAppPurchasePlatformAddition {
+
+ /// Retry loading purchase data after an initial failure.
+ ///
+ /// If no results, a `null` value is returned.
+ Future refreshPurchaseVerificationData() async {
+ await IKRequestMaker().startRefreshReceiptRequest();
+ try {
+ final String receipt = await IKReceiptManager.retrieveReceiptData();
+ return PurchaseVerificationData(
+ localVerificationData: receipt,
+ serverVerificationData: receipt,
+ source: kIAPSource);
+ } catch (e) {
+ // ignore: avoid_print
+ print(
+ 'Something is wrong while fetching the receipt, this normally happens when the app is '
+ 'running on a simulator: $e');
+ return null;
+ }
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_product_details.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_product_details.dart
new file mode 100644
index 0000000000000000000000000000000000000000..907dd328854d84c7c96c39d18cc53aaa19823d8b
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_product_details.dart
@@ -0,0 +1,43 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+import '../../iap_kit_wrappers.dart';
+
+/// The class represents the information of a product as registered in the AppGallery Connect
+/// AppGallery.
+class AppGalleryProductDetails extends ProductDetails {
+ /// Creates a new AppStore specific product details object with the provided
+ /// details.
+ AppGalleryProductDetails({
+ required super.id,
+ required super.title,
+ required super.description,
+ required super.price,
+ required super.rawPrice,
+ required super.currencyCode,
+ required this.skProduct,
+ required super.currencySymbol,
+ });
+
+ factory AppGalleryProductDetails.fromIKProduct(IKProductWrapper product) {
+ return AppGalleryProductDetails(
+ id: product.id,
+ title: product.name,
+ description: product.description,
+ price: product.localPrice,
+ rawPrice: product.microPrice / 1000000.0,
+ currencyCode: product.currency,
+ currencySymbol: product.localPrice.isNotEmpty
+ ? product.localPrice.replaceAll(RegExp(r'[0-9.]+'), "")
+ : product.currency,
+ skProduct: product,
+ );
+ }
+
+ /// Points back to the [IKProductWrapper] object that was used to generate
+ /// this [AppGalleryProductDetails] object.
+ final IKProductWrapper skProduct;
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_details.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_details.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b77ba6d569827b1b2e28f2510702aa1f5396d307
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_details.dart
@@ -0,0 +1,79 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+import '../../iap_kit_wrappers.dart';
+import '../../in_app_purchase_ohos.dart';
+import '../iap_kit_wrappers/enum_converters.dart';
+
+/// The class represents the information of a purchase made with the IAP Kit
+/// AppGallery.
+class AppGalleryPurchaseDetails extends PurchaseDetails {
+ /// Creates a new AppStore specific purchase details object with the provided
+ /// details.
+ AppGalleryPurchaseDetails({
+ super.purchaseID,
+ required super.productID,
+ required super.verificationData,
+ required super.transactionDate,
+ required this.ikPaymentTransaction,
+ required PurchaseStatus status,
+ }) : super(status: status) {
+ this.status = status;
+ }
+
+ factory AppGalleryPurchaseDetails.fromIKTransaction(
+ IKPaymentTransactionWrapper transaction,
+ String base64EncodedReceipt,
+ ) {
+ print('MethodCallHandlerImpl AppGalleryPurchaseDetails.fromIKTransaction ');
+ final AppGalleryPurchaseDetails purchaseDetails = AppGalleryPurchaseDetails(
+ productID: transaction.payment.productId,
+ purchaseID: transaction.transactionIdentifier,
+ ikPaymentTransaction: transaction,
+ status: const IKTransactionStatusConverter()
+ .toPurchaseStatus(transaction.transactionState, transaction.error),
+ transactionDate: transaction.transactionTimeStamp != null
+ ? (transaction.transactionTimeStamp! * 1000).toInt().toString()
+ : null,
+ verificationData: PurchaseVerificationData(
+ localVerificationData: base64EncodedReceipt,
+ serverVerificationData: base64EncodedReceipt,
+ source: kIAPSource),
+ );
+ var statuus = purchaseDetails.status;
+ if (purchaseDetails.status == PurchaseStatus.error ||
+ purchaseDetails.status == PurchaseStatus.canceled) {
+ purchaseDetails.error = IAPError(
+ source: kIAPSource,
+ code: kPurchaseErrorCode,
+ message: transaction.error?.domain ?? '',
+ details: transaction.error?.userInfo,
+ );
+ }
+ return purchaseDetails;
+ }
+
+ /// Points back to the [IKPaymentTransactionWrapper] which was used to
+ /// generate this [AppStorePurchaseDetails] object.
+ final IKPaymentTransactionWrapper ikPaymentTransaction;
+
+ late PurchaseStatus _status;
+
+ /// The status that this [PurchaseDetails] is currently on.
+ @override
+ PurchaseStatus get status => _status;
+
+ @override
+ set status(PurchaseStatus status) {
+ _pendingCompletePurchase = status == PurchaseStatus.purchased;
+ _status = status;
+ }
+
+ bool _pendingCompletePurchase = false;
+
+ @override
+ bool get pendingCompletePurchase => _pendingCompletePurchase;
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_param.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_param.dart
new file mode 100644
index 0000000000000000000000000000000000000000..556acab0925a298d23dd341a6b1bb65bad05fa7a
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/app_gallery_purchase_param.dart
@@ -0,0 +1,18 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
+
+/// Apple AppStore specific parameter object for generating a purchase.
+class AppGalleryPurchaseParam extends PurchaseParam {
+ /// Creates a new [AppGalleryPurchaseParam] object with the given data.
+ AppGalleryPurchaseParam({
+ required super.productDetails,
+ super.applicationUserName,
+ this.quantity = 1,
+ });
+
+ /// Quantity of the product user requested to buy.
+ final int quantity;
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/types.dart b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/types.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1704a2e9ca59ead77b8dcdf50682906db026f383
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/lib/src/types/types.dart
@@ -0,0 +1,7 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+export 'app_gallery_product_details.dart';
+export 'app_gallery_purchase_details.dart';
+export 'app_gallery_purchase_param.dart';
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/.gitignore b/packages/in_app_purchase/in_app_purchase_ohos/ohos/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/BuildProfile.ets b/packages/in_app_purchase/in_app_purchase_ohos/ohos/BuildProfile.ets
new file mode 100644
index 0000000000000000000000000000000000000000..fde84590b4cebb8b75f4d038e944f120c643fe2c
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/BuildProfile.ets
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/**
+ * Use these variables when you tailor your ArkTS code. They must be of the const type.
+ */
+export const HAR_VERSION = '1.0.0';
+export const BUILD_MODE_NAME = 'debug';
+export const DEBUG = true;
+export const TARGET_NAME = 'default';
+
+/**
+ * BuildProfile Class is used only for compatibility purposes.
+ */
+export default class BuildProfile {
+ static readonly HAR_VERSION = HAR_VERSION;
+ static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
+ static readonly DEBUG = DEBUG;
+ static readonly TARGET_NAME = TARGET_NAME;
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/Index.ets b/packages/in_app_purchase/in_app_purchase_ohos/ohos/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..8e39f7c8d0372cd1c4654dec5429fb2317a5740e
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/Index.ets
@@ -0,0 +1,17 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { InAppPurchasePlugin } from './src/main/ets/components/InAppPurchasePlugin'
+export default InAppPurchasePlugin
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/build-profile.json5 b/packages/in_app_purchase/in_app_purchase_ohos/ohos/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..e6773f9f5d76a66d6d19fddc9c6ddb3f5621d3b1
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/build-profile.json5
@@ -0,0 +1,31 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ },
+ "consumerFiles": [
+ "./consumer-rules.txt"
+ ]
+ }
+ },
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest"
+ }
+ ]
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/consumer-rules.txt b/packages/in_app_purchase/in_app_purchase_ohos/ohos/consumer-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/hvigorfile.ts b/packages/in_app_purchase/in_app_purchase_ohos/ohos/hvigorfile.ts
new file mode 100644
index 0000000000000000000000000000000000000000..12a327db0aeeb9462eb1dc098f5e808df40e3dce
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/hvigorfile.ts
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { harTasks } from '@ohos/hvigor-ohos-plugin';
+
+export default {
+ system: harTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
+ plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/obfuscation-rules.txt b/packages/in_app_purchase/in_app_purchase_ohos/ohos/obfuscation-rules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/obfuscation-rules.txt
@@ -0,0 +1,23 @@
+# Define project specific obfuscation rules here.
+# You can include the obfuscation configuration files in the current module's build-profile.json5.
+#
+# For more details, see
+# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# Obfuscation options:
+# -disable-obfuscation: disable all obfuscations
+# -enable-property-obfuscation: obfuscate the property names
+# -enable-toplevel-obfuscation: obfuscate the names in the global scope
+# -compact: remove unnecessary blank spaces and all line feeds
+# -remove-log: remove all console.* statements
+# -print-namecache: print the name cache that contains the mapping from the old names to new names
+# -apply-namecache: reuse the given cache file
+
+# Keep options:
+# -keep-property-name: specifies property names that you want to keep
+# -keep-global-name: specifies names that you want to keep in the global scope
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/oh-package.json5 b/packages/in_app_purchase/in_app_purchase_ohos/ohos/oh-package.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4c93b2c90164676de09d712d7ba79512dfac8961
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/oh-package.json5
@@ -0,0 +1,11 @@
+{
+ "name": "in_app_purchase",
+ "version": "1.0.0",
+ "description": "Please describe the basic information.",
+ "main": "Index.ets",
+ "author": "",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@ohos/flutter_ohos": "file:../libs/flutter.har"
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/JWTUtil.ts b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/JWTUtil.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6f87f4dbc22f2e9acb972ac3ac0b769e3e6b5bbd
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/JWTUtil.ts
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2024 Huawei Technologies Co., Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+import { util } from '@kit.ArkTS';
+
+const centerLineRegex: RegExp = new RegExp('-', 'g');
+const underLineRegex: RegExp = new RegExp('_', 'g');
+const textDecoder = util.TextDecoder.create("utf-8", { ignoreBOM: true });
+const base64 = new util.Base64Helper();
+const TAG: string = 'JWTUtil';
+
+const BASE64_PAD_MOD = 4;
+const BASE64_PAD_INVALID = 1;
+
+export class JWTUtil {
+ public static base64Decode(input: string) {
+ return textDecoder.decodeWithStream(base64.decodeSync(input));
+ }
+
+ private static base64UrlDecode(input: string) {
+ input = input
+ .replace(centerLineRegex, '+')
+ .replace(underLineRegex, '/');
+
+ // Pad out with standard base64 required padding characters
+ const pad = input.length % BASE64_PAD_MOD;
+ if (pad) {
+ if (pad === BASE64_PAD_INVALID) {
+ throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
+ }
+ input += new Array(5 - pad).join('=');
+ }
+ return this.base64Decode(input);
+ }
+
+ public static decodeJwtObj(data: string) {
+ let jwt: string[] = data.split(".");
+ let exp: string = "";
+ if (jwt.length < 3) {
+ return exp;
+ }
+ try {
+ exp = JWTUtil.base64UrlDecode(jwt[1]);
+ } catch (err) {
+ console.error(TAG, 'decodeJwtObj parse err: ' + JSON.stringify(err));
+ }
+ return exp;
+ }
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/TsUtil.ts b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/TsUtil.ts
new file mode 100644
index 0000000000000000000000000000000000000000..17ddb00ee72c59457f8c257ef9175c139ed6720f
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/common/TsUtil.ts
@@ -0,0 +1,24 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+export function ObjToMap(obj: Object): Map {
+ const map = new Map();
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ map.set(key, obj[key]);
+ }
+ }
+ return map
+}
\ No newline at end of file
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/InAppPurchasePlugin.ets b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/InAppPurchasePlugin.ets
new file mode 100644
index 0000000000000000000000000000000000000000..acc2a6683ac2115b91ceb8988fd05dc248296b34
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/InAppPurchasePlugin.ets
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import {
+ AbilityAware,
+ AbilityPluginBinding,
+ FlutterPlugin,
+ FlutterPluginBinding,
+ BinaryMessenger,
+ Log,
+ MethodChannel,
+} from '@ohos/flutter_ohos';
+import { common } from '@kit.AbilityKit';
+import { MethodCallHandlerImpl } from './MethodCallHandlerImpl';
+
+const TAG = "InAppPurchasePlugin"
+
+export class InAppPurchasePlugin implements FlutterPlugin, AbilityAware {
+ private methodChannel: MethodChannel | null = null
+ private methodCallHandler: MethodCallHandlerImpl | null = null
+ private context: common.UIAbilityContext | null = null
+
+ onAttachedToEngine(binding: FlutterPluginBinding): void {
+ this.setUpMethodChannel(binding.getBinaryMessenger(), binding.getApplicationContext());
+ }
+
+ onDetachedFromEngine(binding: FlutterPluginBinding): void {
+ this.teardownMethodChannel();
+ }
+
+ onAttachedToAbility(binding: AbilityPluginBinding): void {
+ this.context = binding.getAbility().context
+ this.methodCallHandler?.setContext(this.context)
+ }
+
+ onDetachedFromAbility(): void {
+ this.methodCallHandler?.setContext(null)
+ }
+
+ getUniqueClassName(): string {
+ return TAG
+ }
+
+ setUpMethodChannel(messenger: BinaryMessenger, context: common.Context) {
+ this.methodChannel = new MethodChannel(messenger, "plugins.flutter.io/in_app_purchase");
+ this.methodCallHandler =
+ new MethodCallHandlerImpl(context, this.methodChannel);
+ this.methodChannel.setMethodCallHandler(this.methodCallHandler);
+ }
+
+ teardownMethodChannel() {
+ this.methodChannel?.setMethodCallHandler(null);
+ this.methodChannel = null;
+ this.methodCallHandler = null;
+ this.context = null;
+ }
+}
diff --git a/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/MethodCallHandlerImpl.ets b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/MethodCallHandlerImpl.ets
new file mode 100644
index 0000000000000000000000000000000000000000..28b3aeff9beb0345c645ce9998560b3a35ba54b1
--- /dev/null
+++ b/packages/in_app_purchase/in_app_purchase_ohos/ohos/src/main/ets/components/MethodCallHandlerImpl.ets
@@ -0,0 +1,288 @@
+/*
+* Copyright (c) 2024 SwanLink (Jiangsu) Technology Development Co., LTD.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { MethodCall, MethodCallHandler, MethodChannel, MethodResult, Log, Any } from '@ohos/flutter_ohos';
+import { MethodNames } from './MethodNames';
+import { iap } from '@kit.IAPKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { common } from '@kit.AbilityKit';
+import { ProductType } from './ProductType';
+import { JWTUtil } from '../common/JWTUtil';
+import { PurchaseOrderPayload, PurchaseSubGroupStatusPayload } from './PurchaseOrderPayload';
+import { HashMap } from '@kit.ArkTS';
+import { TransactionState } from './TransactionState';
+import { PurchaseData } from './PurchaseData';
+import { ObjToMap } from '../common/TsUtil';
+
+const TAG = "MethodCallHandlerImpl"
+
+export class IKError {
+ code: number = 0
+ domain: string = ''
+ userInfo: Map = new Map()
+}
+
+export class MethodCallHandlerImpl implements MethodCallHandler {
+ private context: common.UIAbilityContext | null = null
+ private methodChannel: MethodChannel
+ private observer: MethodChannel | null = null
+ private productDetailsMap: HashMap = new HashMap()
+
+ constructor(context: common.Context, methodChannel: MethodChannel) {
+ this.methodChannel = methodChannel
+ }
+
+ setContext(context: common.UIAbilityContext | null) {
+ this.context = context
+ }
+
+ onMethodCall(call: MethodCall, result: MethodResult): void {
+ switch (call.method) {
+ case MethodNames.START_OBSERVING_TRANSACTION_QUEUE:
+ this.startObserver()
+ break;
+ case MethodNames.STOP_OBSERVING_TRANSACTION_QUEUE:
+ this.stopObserver()
+ break;
+ case MethodNames.QUERY_ENVIRONMENT_STATUS:
+ this.isFeatureSupported(result)
+ break;
+ case MethodNames.QUERY_PRODUCTS:
+ let productList: Array = call.args as Array ?? []
+ this.queryProductDetails(productList, result)
+ break;
+ case MethodNames.CREATE_PURCHASE:
+ this.purchaseGoods(call.args, result)
+ break;
+ case MethodNames.RETRIEVE_RECEIPT_DATA:
+ result.success(null)
+ break;
+ case MethodNames.FINISH_PURCHASE:
+ this.iapFinishPurchase(call, result)
+ break;
+ default:
+ result.notImplemented();
+ }
+ }
+
+ isFeatureSupported(result: MethodResult): void {
+ try {
+ iap.queryEnvironmentStatus(this.context).then(() => {
+ result.success(true);
+ }).catch((err: BusinessError) => {
+ Log.e(TAG, `Failed to query environment status. Code is ${err.code}, message is ${err.message}`);
+ result.success(false);
+ })
+ } catch (e) {
+ Log.e(TAG, `Failed to query environment status. err: ${JSON.stringify(e)}`);
+ result.success(false);
+ }
+ }
+
+ queryProductDetails(list: Array, result: MethodResult) {
+ let productList: Array