Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5c3e8cd
Add macOS Support
rebarah Sep 5, 2021
50423fc
fix "FIAP" misspelling in symolic link
rebarah Sep 5, 2021
bc4742d
Add Target check for ReceiptManager
rebarah Sep 5, 2021
d3bab94
Migrate main dart interfaces
rebarah Sep 5, 2021
75a68e9
migrate types
rebarah Sep 5, 2021
396bd22
migrate store kit wrappers
rebarah Sep 5, 2021
f517312
Add checks for iOS specific apis
rebarah Sep 5, 2021
9c1b8ca
add instancer in main interface
rebarah Sep 5, 2021
dd31d7a
Check iOS Interfaces for QueueHandler
rebarah Sep 5, 2021
f7d540d
Migrate Tests
rebarah Sep 5, 2021
4bf1e47
Adjust changelog for macOS
rebarah Sep 5, 2021
22a2364
Adjust readme
rebarah Sep 5, 2021
9859ed9
fix description in pubspec.yaml
Ahmadre Sep 5, 2021
b0e89c3
Add macOS Support
Ahmadre Sep 5, 2021
71e97e6
Merge commit 'b0e89c3d'
Ahmadre Sep 5, 2021
d2b0069
Merge commit 'b0e89c3d'
Ahmadre Sep 5, 2021
f626439
Merge branch 'master' of https://github.com/Ahmadre/plugins
Ahmadre Sep 5, 2021
90893bf
Merge branch 'master' of https://github.com/Ahmadre/plugins
Ahmadre Sep 5, 2021
30f34a9
Merge branch 'master' of https://github.com/Ahmadre/plugins
Ahmadre Sep 5, 2021
18692b0
clean rebase
Ahmadre Sep 5, 2021
2487b12
format
Ahmadre Sep 5, 2021
2949fcb
format other repos
Ahmadre Sep 5, 2021
19a269b
format objective-c
Ahmadre Sep 5, 2021
035bee9
Migrate example project
Ahmadre Sep 5, 2021
7d204b6
clean macOS platform instances
Ahmadre Sep 5, 2021
12ff934
add git repo to macos dependecy
Ahmadre Sep 5, 2021
875b7ab
First migration to federated plugin for macOS
Ahmadre Sep 5, 2021
ed9d8f1
Remove PaymentQueueDelegate | remove iOS checks
Ahmadre Sep 5, 2021
dc95edd
remove dart interfaces to QueueDelegate
Ahmadre Sep 5, 2021
af61a0e
remove dart apis
Ahmadre Sep 5, 2021
e528027
Update FIAPaymentQueueHandler.m
Ahmadre Sep 5, 2021
6f6cb75
merge ios and macos to storekit
Ahmadre Sep 6, 2021
0c3bdac
fix name
Ahmadre Sep 6, 2021
4640a53
fix default package name
Ahmadre Sep 6, 2021
a90d1f8
fix naming
Ahmadre Sep 6, 2021
1e056de
correct podspec
Ahmadre Sep 6, 2021
685c777
migrate imports
Ahmadre Sep 6, 2021
2e57cf0
merge podspec
Ahmadre Sep 6, 2021
917a367
update platform
Ahmadre Sep 6, 2021
6598b28
add symbolic links
Ahmadre Sep 6, 2021
7d87ac3
Add platform specific podspecs
Ahmadre Sep 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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_ios_platform.dart';
export 'src/in_app_purchase_ios_platform_addition.dart';
export 'src/types/types.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// 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_ios/src/in_app_purchase_ios_platform_addition.dart';
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';

import '../in_app_purchase_ios.dart';
import '../store_kit_wrappers.dart';

/// [IAPError.code] code for failed purchases.
const String kPurchaseErrorCode = 'purchase_error';

/// Indicates store front is Apple AppStore.
const String kIAPSource = 'app_store';

/// An [InAppPurchasePlatform] that wraps StoreKit.
///
/// This translates various `StoreKit` calls and responses into the
/// generic plugin API.
class InAppPurchaseIosPlatform extends InAppPurchasePlatform {
static late SKPaymentQueueWrapper _skPaymentQueueWrapper;
static late _TransactionObserver _observer;

/// Creates an [InAppPurchaseIosPlatform] object.
///
/// This constructor should only be used for testing, for any other purpose
/// get the connection from the [instance] getter.
@visibleForTesting
InAppPurchaseIosPlatform();

Stream<List<PurchaseDetails>> get purchaseStream =>
_observer.purchaseUpdatedController.stream;

/// Callback handler for transaction status changes.
@visibleForTesting
static SKTransactionObserverWrapper get observer => _observer;

/// Registers this class as the default instance of [InAppPurchasePlatform].
static void registerPlatform() {
// Register the [InAppPurchaseIosPlatformAddition] containing iOS
// platform-specific functionality.
InAppPurchasePlatformAddition.instance = InAppPurchaseIosPlatformAddition();

// Register the platform-specific implementation of the idiomatic
// InAppPurchase API.
InAppPurchasePlatform.instance = InAppPurchaseIosPlatform();

_skPaymentQueueWrapper = SKPaymentQueueWrapper();

// Create a purchaseUpdatedController and notify the native side when to
// start of stop sending updates.
StreamController<List<PurchaseDetails>> updateController =
StreamController.broadcast(
onListen: () => _skPaymentQueueWrapper.startObservingTransactionQueue(),
onCancel: () => _skPaymentQueueWrapper.stopObservingTransactionQueue(),
);
_observer = _TransactionObserver(updateController);
_skPaymentQueueWrapper.setTransactionObserver(observer);
}

@override
Future<bool> isAvailable() => SKPaymentQueueWrapper.canMakePayments();

@override
Future<bool> buyNonConsumable({required PurchaseParam purchaseParam}) async {
await _skPaymentQueueWrapper.addPayment(SKPaymentWrapper(
productIdentifier: purchaseParam.productDetails.id,
quantity: 1,
applicationUsername: purchaseParam.applicationUserName,
simulatesAskToBuyInSandbox: (purchaseParam is AppStorePurchaseParam)
? purchaseParam.simulatesAskToBuyInSandbox
: false,
requestData: null));

return true; // There's no error feedback from iOS here to return.
}

@override
Future<bool> buyConsumable(
{required PurchaseParam purchaseParam, bool autoConsume = true}) {
assert(autoConsume == true, 'On iOS, we should always auto consume');
return buyNonConsumable(purchaseParam: purchaseParam);
}

@override
Future<void> completePurchase(PurchaseDetails purchase) {
assert(
purchase is AppStorePurchaseDetails,
'On iOS, the `purchase` should always be of type `AppStorePurchaseDetails`.',
);

return _skPaymentQueueWrapper.finishTransaction(
(purchase as AppStorePurchaseDetails).skPaymentTransaction,
);
}

@override
Future<void> 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 [SKProductResponseWrapper].
@override
Future<ProductDetailsResponse> queryProductDetails(
Set<String> identifiers) async {
final SKRequestMaker requestMaker = SKRequestMaker();
SkProductResponseWrapper response;
PlatformException? exception;
try {
response = await requestMaker.startProductRequest(identifiers.toList());
} on PlatformException catch (e) {
exception = e;
response = SkProductResponseWrapper(
products: [], invalidProductIdentifiers: identifiers.toList());
}
List<AppStoreProductDetails> productDetails = [];
if (response.products != null) {
productDetails = response.products
.map((SKProductWrapper productWrapper) =>
AppStoreProductDetails.fromSKProduct(productWrapper))
.toList();
}
List<String> invalidIdentifiers = response.invalidProductIdentifiers;
if (productDetails.isEmpty) {
invalidIdentifiers = identifiers.toList();
}
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;
}
}

class _TransactionObserver implements SKTransactionObserverWrapper {
final StreamController<List<PurchaseDetails>> purchaseUpdatedController;

Completer? _restoreCompleter;
late String _receiptData;

_TransactionObserver(this.purchaseUpdatedController);

Future<void> restoreTransactions({
required SKPaymentQueueWrapper queue,
String? applicationUserName,
}) {
_restoreCompleter = Completer();
queue.restoreTransactions(applicationUserName: applicationUserName);
return _restoreCompleter!.future;
}

void cleanUpRestoredTransactions() {
_restoreCompleter = null;
}

void updatedTransactions(
{required List<SKPaymentTransactionWrapper> transactions}) async {
String receiptData = await getReceiptData();
List<PurchaseDetails> purchases = transactions
.map((SKPaymentTransactionWrapper transaction) =>
AppStorePurchaseDetails.fromSKTransaction(transaction, receiptData))
.toList();

purchaseUpdatedController.add(purchases);
}

void removedTransactions(
{required List<SKPaymentTransactionWrapper> transactions}) {}

/// Triggered when there is an error while restoring transactions.
void restoreCompletedTransactionsFailed({required SKError error}) {
_restoreCompleter!.completeError(error);
}

void paymentQueueRestoreCompletedTransactionsFinished() {
_restoreCompleter!.complete();
}

bool shouldAddStorePayment(
{required SKPaymentWrapper payment, required SKProductWrapper product}) {
// In this unified API, we always return true to keep it consistent with the behavior on Google Play.
return true;
}

Future<String> getReceiptData() async {
try {
_receiptData = await SKReceiptManager.retrieveReceiptData();
} catch (e) {
_receiptData = '';
}
return _receiptData;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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_ios/in_app_purchase_ios.dart';
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';

import '../store_kit_wrappers.dart';

/// Contains InApp Purchase features that are only available on iOS.
class InAppPurchaseIosPlatformAddition extends InAppPurchasePlatformAddition {
/// Present Code Redemption Sheet.
///
/// Available on devices running iOS 14 and iPadOS 14 and later.
Future presentCodeRedemptionSheet() {
return SKPaymentQueueWrapper().presentCodeRedemptionSheet();
}

/// Retry loading purchase data after an initial failure.
///
/// If no results, a `null` value is returned.
Future<PurchaseVerificationData?> refreshPurchaseVerificationData() async {
await SKRequestMaker().startRefreshReceiptRequest();
try {
String receipt = await SKReceiptManager.retrieveReceiptData();
return PurchaseVerificationData(
localVerificationData: receipt,
serverVerificationData: receipt,
source: kIAPSource);
} catch (e) {
print(
'Something is wrong while fetching the receipt, this normally happens when the app is '
'running on a simulator: $e');
return null;
}
}

/// Sets an implementation of the [SKPaymentQueueDelegateWrapper].
///
/// The [SKPaymentQueueDelegateWrapper] can be used to inform iOS how to
/// finish transactions when the storefront changes or if the price consent
/// sheet should be displayed when the price of a subscription has changed. If
/// no delegate is registered iOS will fallback to it's default configuration.
/// See the documentation on StoreKite's [`-[SKPaymentQueue delegate:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/3182429-delegate?language=objc).
///
/// When set to `null` the payment queue delegate will be removed and the
/// default behaviour will apply (see [documentation](https://developer.apple.com/documentation/storekit/skpaymentqueue/3182429-delegate?language=objc)).
Future setDelegate(SKPaymentQueueDelegateWrapper? delegate) =>
SKPaymentQueueWrapper().setDelegate(delegate);

/// Shows the price consent sheet if the user has not yet responded to a
/// subscription price change.
///
/// Use this function when you have registered a [SKPaymentQueueDelegateWrapper]
/// (using the [setDelegate] method) and returned `false` when the
/// `SKPaymentQueueDelegateWrapper.shouldShowPriceConsent()` method was called.
///
/// See documentation of StoreKit's [`-[SKPaymentQueue showPriceConsentIfNeeded]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/3521327-showpriceconsentifneeded?language=objc).
Future showPriceConsentIfNeeded() =>
SKPaymentQueueWrapper().showPriceConsentIfNeeded();
}
Loading