Quinn, thank you so much for your help. As you can tell endecotp and I tried to get this done by reading the developer documentation but there is a lot missing. A more complete set of documentation would be great.
The name-Swift.h header doesn't have a declaration for the verification function. What's wrong?
Post
Replies
Boosts
Views
Activity
No, endecotp, I can check what it's running on at run-time but that's not the problem. You can't build the project using AppTransaction unless you target at least 13. And there are some conversations about @available on these forums but not in the developer documentation.
Also if you target something like 10.15 you will get a whole bunch of compiler warnings about the security functions in your verification code being deprecated.
[MyAppTransaction checkReceiptWithCompletionHandler:^(NSString * _Nonnull status) {
NSLog(@"status: %@", status);
}];
Won't build - unknown object MyAppTransaction. Maybe some guidance about what to put in the bridging header would help?
XCode didn't automatically add the bridging header to my target so doing this fixed that issue. but the project won't build because AppTransaction isn't available for my build target 10.11.
Quinn, your procedure doesn't work:
When I create the Swift file, XCode doesn't ask me if I want to create a bridging header. The project won't build without it. Also XCode asks me what I want to subclass. Is NSObject right?
The project won't compile without projectname-Swift.h
Manually creating a projectname-Swift.h seems to work - it is filled in by XCode.
The project won't build without projectname-Bridging-Header.h. Manually creating it and adding it to the project seems to work - XCode fills it in but I get an error:
"Did you forget to declare this file as an output of a script phase or custom build rule which produces it?"
Huh? Isn't this a header file I can #import into my project?
Also the undocumented API @available doesn't look usable because it checks the environment at runtime. What I would need would be conditional compilation, right?
Quinn, your code won't compile :
let verificationResult = try await AppTransaction.shared
reports an error:
AppTransaction is only available in macOS 13 or newer.
I'm running on 15.0.1 so It looks like I can only use AppTransaction if I target 13 or later. If I do this it is likely that my program will crash when some users launch it. bummer...
AppTransaction is available on macOS 13. If you are supporting users on earlier OSes you have to check for this and use the (deprecated?) receipt validation technique. I use this:
BOOL runningOnAtleast(int majorVersion, int minorVersion, int patchVersion)
{
NSOperatingSystemVersion OSVersion; //struct with three variables declared as NSIntegers:
OSVersion.majorVersion = majorVersion;
OSVersion.minorVersion = minorVersion;
OSVersion.patchVersion = patchVersion;
return [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: OSVersion];
}
All I need to do is execute one line of Swift:
let verificationResult = try await AppTransaction.shared
and look at verification result.
According to the less-than-worthless documentation here:
https://developer.apple.com/documentation/swift/importing-swift-into-objective-c
“You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file.” Generating the header file and including it in my project and .m file doesn't make XCode recognize the types.
Theoretically you could call some C version of the above line from your .m file. Carefully following the incomplete documentation I can’t do it so Xcode will recognize the three types, verificationResult (also spelled as VerificationResult, upper case ‘V’ in the documentation), AppTransaction and its method, shared. Including AppTransaction (and verificationResult and shared) in my .m code results in a error:
Use of undeclared identifier ‘AppTransaction’ (all three types); XCode doesn't complain about the syntax, it just doesn't recognize the types.
Your advice not to try to call StoreKit’s Swift functions directly from objC is good, since it’s not really possible using the developer documentation.
The documentation here:
https://developer.apple.com/documentation/swift/migrating-your-objective-c-code-to-swift/
Tells me how to sub-class an Objective-C class in Swift to use it in an Objective-C project, but not to do what you describe “Write a short Swift function that calls StoreKit, and call that from objC”.
Maybe you know about some documentation describing how to do this?
There's a discusion about this here:
https://developer.apple.com/forums/thread/764537?answerId=809709022#809709022
Good questions - The developer documentation says that the easiest way to do it is to use the Swift struct AppTransaction. If you can actually figure out how to do it, you are smarter than me and a whole lot of other developers. Please post your code if you figure this out.
Also I included the StoreKit.framework and SwiftData.framework in my target build settings. Is there some (undocumented?) trick to get XCode to recognize the Store Kit types?
Just to be perfectly clear:
The developer documentation says I can get XCode to generate a header that will allow a .m file to recognize Swift types and key words.
I carefully followed the instructions - I got it to create the header. I included the header in my project. I imported the header into my .m file. I am including the Store Kit framework in my build settings. I imported the header storekit/storekit.h in my file.
It doesn't matter how I try to use AppTransaction because XCode doesn't recognize Swift ketwords of types.
I can write a Swift function to verify the receipt:
func chekReceipt() async{
do{
let verificationResult = try await AppTransaction.shared
switch verificationResult {
case .verified(let appTransaction):
var string = "receipt verified"
print(string)
case .unverified(let appTransaction, let verificationError):
var string = "receipt unverified"
print(string)
}
}
catch{
var string = "checkReceipt threw an error"
print(string)
}
}
But I can't call it from Objective C.
There are other issues: I am targeting my project for macOS 10.11 (the earliest version you can target with XCode) to provide backwards compatibility. Lots of my users are on older Macs and don't use 10.15. AppTransaction is only available on 10.13+ so I will have to support the older verification code for a long time and if Apple breaks this it will be a hassle for me and my users.
Also the sample code for AppTransaction won't build. You have to add the keyword "async". This is not in my book Swift Programming 3rd Edition or the sample code so I had to go through a bunch of ** to figure this out. Criticism of Swift - it's a moving target.
I have made some progress. I added the forward declaration:
@class AppTransaction;
@interface AppTransaction : NSObject
- (AppTransaction *)returnAppTransaction;
@end
to myappname-Swift.h header.
Now XCode recognizes AppTransaction in my code. BUT AppTransaction is declared as struct and XCode doesn't recognize .shared or .VerificationResult. members.
If I remove the declaration, XCode won't recognize AppTransaction - undeclaredidentifier.
After carefully studying the documentation for Importing Swift into Objective-C, I am unable to make it work.
First of all the document says that the header is generated from my Product Module name. Searching the Developer documentation and the XCode Help for Product Module Name yields no results. Looking at my project's Target Build Settings I see in Packaging a field called Product Module Name. Since this is the closest thing I can find to the description in the document I put the name of my app in the fields.
Then I created a header file with the name appName-Swift.h in my project. I built the project but the header is empty and #importing it into a .m file doesn't provide my code with the Swift types.
Has anyone actually been able to do this as described in the document? For me, carefully studying the developer documentation often brings me to a frustrating dead end like this.
I have the same problems. The app is reporting that exit(173) is no longer available, even though it isn't called. The alert tells me to use Transaction or AppTransaction. These are only available in Swift and they are for in-app purchases. The documentation tells me to use AppTransaction or Transaction. These are also Swift but not objective C APIs. I have created a header as described in the documentation for Importing Swift into Objective-C but this is not helpful because I need to read the Objective C declarations to call the Swift APIs from my Objective C code. I can't because the productname-Swift.h file is empty. It does seem to understand Objective-C versions of some APIs, such as NSPersistentHistoryTransaction *myTransaction but making wild guesses about the APIs in Objective-C isn't the real way to do this. All I need t do is call the method to validate the receipt and also if there is some way to get a test receipt to debug my code as I did with exit(173) it would be a help.