Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, FIAInAppPurchaseAPI {
SetUpFIAInAppPurchaseAPI(messenger, instance)
if #available(iOS 15.0, macOS 12.0, *) {
InAppPurchase2APISetup.setUp(binaryMessenger: messenger, api: instance)
#if os(iOS)
registrar.addSceneDelegate(instance)
#endif
}
}

Expand Down Expand Up @@ -465,3 +468,7 @@ public class InAppPurchasePlugin: NSObject, FlutterPlugin, FIAInAppPurchaseAPI {
)
}
}

#if os(iOS)
extension InAppPurchasePlugin: FlutterSceneLifeCycleDelegate {}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,51 @@ extension InAppPurchasePlugin: InAppPurchase2API {
}
}

func presentOfferCodeRedeemSheet(completion: @escaping (Result<Void, Error>) -> Void) {
#if os(iOS)
if #available(iOS 16.0, *) {
guard let windowScene = self.registrar?.viewController?.view.window?.windowScene else {
let error = PigeonError(
code: "storekit2_missing_key_window_scene",
message: "Failed to fetch key window scene",
details: "registrar.viewController.view.window.windowScene returned nil."
)
completion(.failure(error))
return
}
Task { @MainActor in
do {
try await AppStore.presentOfferCodeRedeemSheet(in: windowScene)
completion(.success(()))
} catch {
completion(.failure(error))
}
}
}
#elseif os(macOS)
if #available(macOS 15.0, *) {
guard let viewController = self.registrar?.viewController else {
let error = PigeonError(
code: "storekit2_missing_view_controller",
message: "Failed to fetch view controller",
details: "registrar.viewController returned nil."
)
completion(.failure(error))
return
}

Task { @MainActor in
do {
try await AppStore.presentOfferCodeRedeemSheet(from: viewController)
completion(.success(()))
} catch {
completion(.failure(error))
}
}
}
#endif
}

/// Wrapper method around StoreKit2's sync() method
/// https://developer.apple.com/documentation/storekit/appstore/sync()
/// When called, a system prompt will ask users to enter their authentication details
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autogenerated from Pigeon (v26.1.5), do not edit directly.
// Autogenerated from Pigeon (v26.1.10), do not edit directly.
// See also: https://pub.dev/packages/pigeon

import Foundation
Expand Down Expand Up @@ -759,6 +759,7 @@ protocol InAppPurchase2API {
func restorePurchases(completion: @escaping (Result<Void, Error>) -> Void)
func countryCode(completion: @escaping (Result<String, Error>) -> Void)
func sync(completion: @escaping (Result<Void, Error>) -> Void)
func presentOfferCodeRedeemSheet(completion: @escaping (Result<Void, Error>) -> Void)
}

/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
Expand Down Expand Up @@ -1008,6 +1009,24 @@ class InAppPurchase2APISetup {
} else {
syncChannel.setMessageHandler(nil)
}
let presentOfferCodeRedeemSheetChannel = FlutterBasicMessageChannel(
name:
"dev.flutter.pigeon.in_app_purchase_storekit.InAppPurchase2API.presentOfferCodeRedeemSheet\(channelSuffix)",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
presentOfferCodeRedeemSheetChannel.setMessageHandler { _, reply in
api.presentOfferCodeRedeemSheet { result in
switch result {
case .success:
reply(wrapResult(nil))
case .failure(let error):
reply(wrapError(error))
}
}
}
} else {
presentOfferCodeRedeemSheetChannel.setMessageHandler(nil)
}
}
}
/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,11 +733,11 @@ void SetUpFIAInAppPurchaseAPIWithSuffix(id<FlutterBinaryMessenger> binaryMesseng
binaryMessenger:binaryMessenger
codec:FIAGetMessagesCodec()];
if (api) {
NSCAssert([api respondsToSelector:@selector(startProductRequestProductIdentifiers:
completion:)],
@"FIAInAppPurchaseAPI api (%@) doesn't respond to "
@"@selector(startProductRequestProductIdentifiers:completion:)",
api);
NSCAssert(
[api respondsToSelector:@selector(startProductRequestProductIdentifiers:completion:)],
@"FIAInAppPurchaseAPI api (%@) doesn't respond to "
@"@selector(startProductRequestProductIdentifiers:completion:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray<id> *args = message;
NSArray<NSString *> *arg_productIdentifiers = GetNullableObjectAtIndex(args, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@
21CE6E615CF661FC0E18FB0A /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
6458340B2CE3497379F6B389 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = "<group>"; };
78DABEA22ED26510000E7860 /* in_app_purchase_storekit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = in_app_purchase_storekit; path = ../../darwin/in_app_purchase_storekit; sourceTree = "<group>"; };
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
7AB7758EFACBE3E1E7BDE0C6 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -138,8 +136,6 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
78DABEA22ED26510000E7860 /* in_app_purchase_storekit */,
784666492D4C4C64000A1A5F /* FlutterFramework */,
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
Expand Down Expand Up @@ -307,7 +303,7 @@
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -588,8 +584,10 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -604,8 +602,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.inAppPurchaseExample;
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.inAppPurchaseExample9;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
Expand All @@ -615,8 +614,10 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = S8QB4VV633;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -631,8 +632,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.inAppPurchaseExample;
PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.inAppPurchaseExample9;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
Expand All @@ -649,8 +651,9 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = S8QB4VV633;
INFOPLIST_FILE = RunnerTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -680,8 +683,9 @@
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
DEVELOPMENT_TEAM = S8QB4VV633;
INFOPLIST_FILE = RunnerTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand Down Expand Up @@ -730,7 +734,7 @@
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<MacroExpansion>
Expand Down Expand Up @@ -73,6 +74,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>

@interface AppDelegate : FlutterAppDelegate
@interface AppDelegate : FlutterAppDelegate <FlutterImplicitEngineDelegate>

@end
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ @implementation AppDelegate

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)didInitializeImplicitFlutterEngine:(NSObject<FlutterImplicitEngineBridge> *)engineBridge {
[GeneratedPluginRegistrant registerWithRegistry:engineBridge.pluginRegistry];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
Expand All @@ -22,6 +24,29 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneDelegateClassName</key>
<string>FlutterSceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
Expand All @@ -39,9 +64,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class _MyAppState extends State<_MyApp> {
_buildConnectionCheckTile(),
_buildProductList(),
_buildConsumableBox(),
_buildCodeRedemptionButton(),
_buildRestoreButton(),
],
),
Expand Down Expand Up @@ -429,6 +430,30 @@ class _MyAppState extends State<_MyApp> {
);
}

Widget _buildCodeRedemptionButton() {
if (_loading) {
return Container();
}

return Padding(
padding: const EdgeInsets.all(4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
TextButton(
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Colors.white,
),
onPressed: () =>
_iapStoreKitPlatformAddition.presentCodeRedemptionSheet(),
child: const Text('Show code redemption sheet'),
),
],
),
);
}

Widget _buildRestoreButton() {
if (_loading) {
return Container();
Expand Down
Loading
Loading