Skip to content

Commit

Permalink
Implement support of handling dropped success purchase.
Browse files Browse the repository at this point in the history
This is similar feature from react-native-iap(dooboolab-community/react-native-iap#307). Similar issue in current repo #54.
  • Loading branch information
hyochan committed Jan 28, 2019
1 parent 192277a commit bd13457
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 13 deletions.
4 changes: 0 additions & 4 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
27672194C9D5FA8DDDF731B8 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A72A37C715E27BACEF745D36 /* libPods-Runner.a */; };
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -42,7 +41,6 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -85,7 +83,6 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
Expand Down Expand Up @@ -214,7 +211,6 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
3 changes: 3 additions & 0 deletions ios/Classes/FlutterInappPurchasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ -(void)purchaseProcess:(SKPaymentTransaction *)transaction {
[requestedPayments removeObjectForKey:transaction.payment];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

// additionally send event
[self.channel invokeMethod:@"iap-purchase-event" arguments: purchase];
}

- (NSDictionary *)getPurchaseData:(SKPaymentTransaction *)transaction {
Expand Down
70 changes: 61 additions & 9 deletions lib/flutter_inapp_purchase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class FlutterInappPurchase {
'subs',
];

static StreamController<PurchasedItem> _purchaseController;
static StreamSubscription _purchaseSub;
static Stream<PurchasedItem> get onAdditionalSuccessPurchaseIOS => _purchaseController.stream;

/// Defining the [MethodChannel] for Flutter_Inapp_Purchase
static const MethodChannel _channel = const MethodChannel('flutter_inapp');

Expand Down Expand Up @@ -213,15 +217,27 @@ class FlutterInappPurchase {

return item;
} else if (Platform.isIOS) {
dynamic result = await _channel.invokeMethod<dynamic>(
'buyProductWithFinishTransaction', <String, dynamic>{
'sku': sku,
});
result = json.encode(result);

Map<String, dynamic> param = json.decode(result.toString());
PurchasedItem item = PurchasedItem.fromJSON(param);
return item;
try {
dynamic result = await _channel.invokeMethod<dynamic>(
'buyProductWithFinishTransaction', <String, dynamic>{
'sku': sku,
});
result = json.encode(result);

Map<String, dynamic> param = json.decode(result.toString());
PurchasedItem item = PurchasedItem.fromJSON(param);
return item;
} catch (err) {
print('Caused err. Set additionalSuccessPurchaseListenerIOS.');
print(err);
await _addAdditionalSuccessPurchaseListenerIOS();
_purchaseSub = onAdditionalSuccessPurchaseIOS.listen((data) {
_removePurchaseListener();
Map<String, dynamic> param = json.decode(data.toString());
PurchasedItem item = PurchasedItem.fromJSON(param);
return item;
});
}
}
throw PlatformException(
code: Platform.operatingSystem, message: "platform not supported");
Expand Down Expand Up @@ -461,4 +477,40 @@ class FlutterInappPurchase {
},
);
}

/// Add additional success purchase listener to iOS when purchase failed
///
/// In iOS, purchase could be failed randomly. See the reference: https://github.com/dooboolab/react-native-iap/issues/307
/// To make your purchase flow confidential, use below method. Checkout how this is used in `example` project.
static Future<void> _addAdditionalSuccessPurchaseListenerIOS() async {
if (Platform.isIOS) {
if (_purchaseController == null) {
_purchaseController = new StreamController.broadcast();
}
_channel.setMethodCallHandler((MethodCall call) {
switch (call.method) {
case "iap-purchase-event":
Map<String, dynamic> result = jsonDecode(call.arguments);
_purchaseController.add(new PurchasedItem.fromJSON(result));
_removePurchaseListener();
break;
default:
throw new ArgumentError('Unknown method ${call.method}');
}
});
}
}

static Future<void> _removePurchaseListener() async {
if (_purchaseSub != null) {
_purchaseSub.cancel();
_purchaseSub = null;
}
if (_purchaseController != null) {
_purchaseController
..add(null)
..close();
_purchaseController = null;
}
}
}

0 comments on commit bd13457

Please sign in to comment.