Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obfuscated account id #299

Merged
merged 4 commits into from
Jul 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 5.0.2
+ Replaced obfuscatedAccountIdAndroid with obfuscatedAccountId in request purchase method [#299](https://github.com/dooboolab/flutter_inapp_purchase/pull/299)

## 5.0.1
+ Add AndroidProrationMode values [#273](https://github.com/dooboolab/flutter_inapp_purchase/pull/273)

Expand Down
2 changes: 2 additions & 0 deletions ios/Classes/FlutterInappPurchasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
}
} else if ([@"buyProduct" isEqualToString:call.method]) {
NSString* identifier = (NSString*)call.arguments[@"sku"];
NSString* usernameHash = (NSString*)call.arguments[@"forUser"];
SKProduct *product;

for (SKProduct *p in validProducts) {
Expand All @@ -80,6 +81,7 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
}
if (product) {
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
payment.applicationUsername = usernameHash;
[[SKPaymentQueue defaultQueue] addPayment:payment];
} else {
NSDictionary *err = [NSDictionary dictionaryWithObjectsAndKeys:
Expand Down
28 changes: 9 additions & 19 deletions lib/flutter_inapp_purchase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class FlutterInappPurchase {
///
/// `iOS` also returns subscriptions.
Future<List<IAPItem>> getProducts(List<String> skus) async {
if (skus == null || skus.contains(null)) return [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No use as List can't be null and any element of it can't be null as well

skus = skus.toList();
if (_platform.isAndroid) {
dynamic result = await _channel.invokeMethod(
Expand Down Expand Up @@ -128,7 +127,6 @@ class FlutterInappPurchase {
///
/// `iOS` also returns non-subscription products.
Future<List<IAPItem>> getSubscriptions(List<String> skus) async {
if (skus == null || skus.contains(null)) return [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No use as List can't be null and any element of it can't be null as well

skus = skus.toList();
if (_platform.isAndroid) {
dynamic result = await _channel.invokeMethod(
Expand Down Expand Up @@ -219,28 +217,29 @@ class FlutterInappPurchase {

/// Request a purchase on `Android` or `iOS`.
/// Result will be received in `purchaseUpdated` listener or `purchaseError` listener.
///
///
/// Check [AndroidProrationMode] for valid proration values
/// Identical to [requestSubscription] on `iOS`.
Future requestPurchase(
String sku, {
String? obfuscatedAccountIdAndroid,
String? obfuscatedProfileIdAndroid,
String? obfuscatedAccountId,
String? purchaseTokenAndroid,
String? obfuscatedProfileIdAndroid,
}) async {
if (_platform.isAndroid) {
return await _channel.invokeMethod('buyItemByType', <String, dynamic>{
'type': EnumUtil.getValueString(_TypeInApp.inapp),
'sku': sku,
'oldSku': null,
'prorationMode': -1,
'obfuscatedAccountId': obfuscatedAccountIdAndroid,
'obfuscatedAccountId': obfuscatedAccountId,
'obfuscatedProfileId': obfuscatedProfileIdAndroid,
'purchaseToken': purchaseTokenAndroid,
});
} else if (_platform.isIOS) {
return await _channel.invokeMethod('buyProduct', <String, dynamic>{
'sku': sku,
'forUser': obfuscatedAccountId,
});
}
throw PlatformException(
Expand All @@ -251,7 +250,7 @@ class FlutterInappPurchase {
/// Result will be received in `purchaseUpdated` listener or `purchaseError` listener.
///
/// **NOTICE** second parameter is required on `Android`.
///
///
/// Check [AndroidProrationMode] for valid proration values
/// Identical to [requestPurchase] on `iOS`.
Future requestSubscription(
Expand Down Expand Up @@ -506,7 +505,6 @@ class FlutterInappPurchase {
Duration duration: const Duration(days: 30),
Duration grace: const Duration(days: 3),
}) async {
assert(sku != null);
if (_platform.isIOS) {
var history =
await (getPurchaseHistory() as FutureOr<List<PurchasedItem>>);
Expand Down Expand Up @@ -548,9 +546,6 @@ class FlutterInappPurchase {
required Map<String, String> receiptBody,
bool isTest = true,
}) async {
assert(receiptBody != null);
assert(isTest != null);

final String url = isTest
? 'https://sandbox.itunes.apple.com/verifyReceipt'
: 'https://buy.itunes.apple.com/verifyReceipt';
Expand Down Expand Up @@ -587,11 +582,6 @@ class FlutterInappPurchase {
required String accessToken,
bool isSubscription = false,
}) async {
assert(packageName != null);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no use for null safety version

assert(productId != null);
assert(productToken != null);
assert(accessToken != null);

final String type = isSubscription ? 'subscriptions' : 'products';
final String url =
'https://www.googleapis.com/androidpublisher/v3/applications/$packageName/purchases/$type/$productId/tokens/$productToken?access_token=$accessToken';
Expand Down Expand Up @@ -642,7 +632,7 @@ class FlutterInappPurchase {
throw new ArgumentError('Unknown method ${call.method}');
}
return Future.value(null);
} as Future<dynamic> Function(MethodCall)?);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant

});
}

Future _removePurchaseListener() async {
Expand All @@ -663,7 +653,7 @@ class FlutterInappPurchase {

/// A list of valid values for ProrationMode parameter
/// https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode
class AndroidProrationMode{
class AndroidProrationMode {
/// Replacement takes effect when the old plan expires, and the new price will be charged at the same time.
/// https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode#DEFERRED
static const int DEFERRED = 4;
Expand All @@ -682,4 +672,4 @@ class AndroidProrationMode{

/// https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode#unknown_subscription_upgrade_downgrade_policy
static const int UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY = 0;
}
}
63 changes: 33 additions & 30 deletions lib/modules.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,14 @@ class IAPItem {
json['introductoryPriceNumberOfPeriodsIOS'] as String?,
introductoryPriceSubscriptionPeriodIOS =
json['introductoryPriceSubscriptionPeriodIOS'] as String?,
introductoryPriceNumberIOS = json['introductoryPriceNumberIOS'] as String?,
introductoryPriceNumberIOS =
json['introductoryPriceNumberIOS'] as String?,
subscriptionPeriodNumberIOS =
json['subscriptionPeriodNumberIOS'] as String?,
subscriptionPeriodUnitIOS = json['subscriptionPeriodUnitIOS'] as String?,
subscriptionPeriodAndroid = json['subscriptionPeriodAndroid'] as String?,
subscriptionPeriodUnitIOS =
json['subscriptionPeriodUnitIOS'] as String?,
subscriptionPeriodAndroid =
json['subscriptionPeriodAndroid'] as String?,
introductoryPriceCyclesAndroid =
json['introductoryPriceCyclesAndroid'] as int?,
introductoryPricePeriodAndroid =
Expand Down Expand Up @@ -93,13 +96,18 @@ class IAPItem {

data['subscriptionPeriodNumberIOS'] = this.subscriptionPeriodNumberIOS;
data['subscriptionPeriodUnitIOS'] = this.subscriptionPeriodUnitIOS;
data['introductoryPricePaymentModeIOS'] = this.introductoryPricePaymentModeIOS;
data['introductoryPriceNumberOfPeriodsIOS'] = this.introductoryPriceNumberOfPeriodsIOS;
data['introductoryPriceSubscriptionPeriodIOS'] = this.introductoryPriceSubscriptionPeriodIOS;
data['introductoryPricePaymentModeIOS'] =
this.introductoryPricePaymentModeIOS;
data['introductoryPriceNumberOfPeriodsIOS'] =
this.introductoryPriceNumberOfPeriodsIOS;
data['introductoryPriceSubscriptionPeriodIOS'] =
this.introductoryPriceSubscriptionPeriodIOS;

data['subscriptionPeriodAndroid'] = this.subscriptionPeriodAndroid;
data['introductoryPriceCyclesAndroid'] = this.introductoryPriceCyclesAndroid;
data['introductoryPricePeriodAndroid'] = this.introductoryPricePeriodAndroid;
data['introductoryPriceCyclesAndroid'] =
this.introductoryPriceCyclesAndroid;
data['introductoryPricePeriodAndroid'] =
this.introductoryPricePeriodAndroid;
data['freeTrialPeriodAndroid'] = this.freeTrialPeriodAndroid;
data['signatureAndroid'] = this.signatureAndroid;

Expand Down Expand Up @@ -133,8 +141,7 @@ class IAPItem {
'iconUrl: $iconUrl, '
'originalJson: $originalJson, '
'originalPrice: $originalPrice, '
'discounts: $discountsIOS, '
;
'discounts: $discountsIOS, ';
}

static List<DiscountIOS>? _extractDiscountIOS(dynamic json) {
Expand All @@ -144,12 +151,12 @@ class IAPItem {
if (list != null) {
discounts = list
.map<DiscountIOS>(
(dynamic discount) => DiscountIOS.fromJSON(discount as Map<String, dynamic>),
)
(dynamic discount) =>
DiscountIOS.fromJSON(discount as Map<String, dynamic>),
)
.toList();
}


return discounts;
}
}
Expand Down Expand Up @@ -194,8 +201,7 @@ class DiscountIOS {
'price: $price, '
'localizedPrice: $localizedPrice, '
'paymentMode: $paymentMode, '
'subscriptionPeriod: $subscriptionPeriod, '
;
'subscriptionPeriod: $subscriptionPeriod, ';
}
}

Expand Down Expand Up @@ -229,15 +235,13 @@ class PurchasedItem {
transactionReceipt = json['transactionReceipt'] as String?,
purchaseToken = json['purchaseToken'] as String?,
orderId = json['orderId'] as String?,

dataAndroid = json['dataAndroid'] as String?,
signatureAndroid = json['signatureAndroid'] as String?,
isAcknowledgedAndroid = json['isAcknowledgedAndroid'] as bool?,
autoRenewingAndroid = json['autoRenewingAndroid'] as bool?,
purchaseStateAndroid =
_decodePurchaseStateAndroid(json['purchaseStateAndroid'] as int?),
originalJsonAndroid = json['originalJsonAndroid'] as String?,

originalTransactionDateIOS =
_extractDate(json['originalTransactionDateIOS']),
originalTransactionIdentifierIOS =
Expand All @@ -254,13 +258,15 @@ class PurchasedItem {
'transactionReceipt: $transactionReceipt, '
'purchaseToken: $purchaseToken, '
'orderId: $orderId, '

/// android specific
'dataAndroid: $dataAndroid, '
'signatureAndroid: $signatureAndroid, '
'isAcknowledgedAndroid: $isAcknowledgedAndroid, '
'autoRenewingAndroid: $autoRenewingAndroid, '
'purchaseStateAndroid: $purchaseStateAndroid, '
'originalJsonAndroid: $originalJsonAndroid, '

/// ios specific
'originalTransactionDateIOS: ${originalTransactionDateIOS?.toIso8601String()}, '
'originalTransactionIdentifierIOS: $originalTransactionIdentifierIOS, '
Expand All @@ -286,7 +292,7 @@ class PurchaseResult {
this.responseCode,
this.debugMessage,
this.code,
this.message
this.message,
});

PurchaseResult.fromJSON(Map<String, dynamic> json)
Expand All @@ -296,23 +302,21 @@ class PurchaseResult {
message = json['message'] as String?;

Map<String, dynamic> toJson() => {
"responseCode": responseCode ?? 0,
"debugMessage": debugMessage ?? '',
"code": code ?? '',
"message": message ?? '',
};
"responseCode": responseCode ?? 0,
"debugMessage": debugMessage ?? '',
"code": code ?? '',
"message": message ?? '',
};

@override
String toString() {
return 'responseCode: $responseCode, '
'debugMessage: $debugMessage, '
'code: $code, '
'message: $message'
;
'message: $message';
}
}


class ConnectionResult {
final bool? connected;

Expand All @@ -324,13 +328,12 @@ class ConnectionResult {
: connected = json['connected'] as bool?;

Map<String, dynamic> toJson() => {
"connected": connected ?? false,
};
"connected": connected ?? false,
};

@override
String toString() {
return 'connected: $connected'
;
return 'connected: $connected';
}
}

Expand Down
7 changes: 2 additions & 5 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: flutter_inapp_purchase
description: In App Purchase plugin for flutter. This project has been forked by react-native-iap and we are willing to share same experience with that on react-native.
version: 5.0.1
version: 5.0.2
homepage: https://github.com/dooboolab/flutter_inapp_purchase/blob/master/pubspec.yaml
environment:
sdk: '>=2.12.0 <3.0.0'
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.0.0 <3.0.0"

dependencies:
Expand All @@ -20,7 +20,6 @@ dev_dependencies:
flutter_test:
sdk: flutter


# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec

Expand All @@ -33,7 +32,6 @@ flutter:
pluginClass: FlutterInappPurchasePlugin
ios:
pluginClass: FlutterInappPurchasePlugin

# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
Expand All @@ -44,7 +42,6 @@ flutter:
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.

# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
Expand Down
14 changes: 12 additions & 2 deletions test/flutter_inapp_purchase_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ void main() {
};

final String sku = "testsku";
final String forUser = "testObfuscatedUser";

setUp(() {
FlutterInappPurchase(FlutterInappPurchase.private(
Expand All @@ -927,12 +928,16 @@ void main() {
});

test('invokes correct method', () async {
await FlutterInappPurchase.instance.requestPurchase(sku);
await FlutterInappPurchase.instance.requestPurchase(
sku,
obfuscatedAccountId: forUser,
);
expect(log, <Matcher>[
isMethodCall(
'buyProduct',
arguments: <String, dynamic>{
'sku': sku,
'forUser': forUser,
},
),
]);
Expand Down Expand Up @@ -1063,6 +1068,7 @@ void main() {
group('for iOS', () {
final List<MethodCall> log = <MethodCall>[];
final String sku = "testsku";
final String forUser = "testObfuscatedUser";
final dynamic result = {
"transactionDate": "1552824902000",
"transactionId": "testTransactionId",
Expand Down Expand Up @@ -1093,12 +1099,16 @@ void main() {
});

test('invokes correct method', () async {
await FlutterInappPurchase.instance.requestPurchase(sku);
await FlutterInappPurchase.instance.requestPurchase(
sku,
obfuscatedAccountId: forUser,
);
expect(log, <Matcher>[
isMethodCall(
'buyProduct',
arguments: <String, dynamic>{
'sku': sku,
'forUser': forUser,
},
),
]);
Expand Down