Forum Xamarin.iOS
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Submitting to App Store with Receipt Checking

pmhart83pmhart83 USMember ✭✭✭
edited September 2015 in Xamarin.iOS

We have learned that in order to get our Mac app into the App Store we need to check that it's has a valid receipt and that iTunes user obtained it from the App Store.

We have also learned that this is not a common topic and is not really documented by Xamarin.

I did find this topic:
https://forums.xamarin.com/discussion/29794/how-can-i-validate-mac-app-store-receipt-locally

Which got me pointed in the right direction. However Xamarin.Mac by default does not have an "int main()" function. The main function is void. It's unclear how to handle the case that the receipt is invalid in Xamarins C# version of this structure.

Also Xamarin.Mac does not contain a binding project like Xamarin.iOS, so I can not just drop this Objective-C code in. It's really hard to believe that up until now no one has submitted a Xamarin.Mac app to the app store. You'd think this would be a pretty important topic to cover in the online documentation. Especially given the premium cost to have individual Mac developer licenses.

I would love to know if there is a simple solution to getting this validation in our code as all the solutions seem to be complex.

Things I am considering:
1. Writing this big Obj-C class in C# which somehow can call "exit(173)" by thumbing through the code line by line
2. Creating a binding somehow

Can anyone out there save me some time?

Posts

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    I've never done this, at all, but a glance suggests:

  • pmhart83pmhart83 USMember ✭✭✭

    @ChrisHamons

    Thanks for the link to the binding solution. I also found this:
    http://brendanzagaeski.appspot.com/xamarin/0002.html

    I was going to go down that path and assume the binding translates the "exit()" function.

  • pmhart83pmhart83 USMember ✭✭✭

    @ChrisHamons

    Need some help with the clang command. I modified the downloaded zip so that "SimpleClass" was "RVNReceiptValidation" but when I run the following:

    clang -dynamiclib -std=gnu99 RVNReceiptValidation.m -current_version 1.0 -compatibility_version 1.0 -fvisibility=hidden -framework Cocoa -o bin/RVNReceiptValidation.dylib

    I get a huge list of errors:

    Undefined symbols for architecture x86_64:
    "_CMSDecoderCopyContent", referenced from:
    _RVNDecodeReceiptData in RVNReceiptValidation-1084f1.o
    "_CMSDecoderCopySignerStatus", referenced from:
    _RVNDecodeReceiptData in RVNReceiptValidation-1084f1.o
    "_CMSDecoderCreate", referenced from:
    _RVNDecodeReceiptData in RVNReceiptValidation-1084f1.o
    ...
    "_kSecAsn1UTF8StringTemplate", referenced from:
    _RVNDecodeUTF8StringFromASN1Data in RVNReceiptValidation-1dd8e6.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    I am not an expert on compilers so I am pretty confused. My guess was I need to reference the Security framework? But it seems like it's included in Cocoa?

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    Yeah, it appears to live there:

    https://developer.apple.com/library/mac/documentation/Security/Reference/CryptoMessageRef/#//apple_ref/c/func/CMSDecoderCopyContent

    Often, an easy way to figure out the command line arguments to, is create a new project in Xcode. Add the frameworks you need and a reference to each symbol. Then build and click the "Show report navigator on the left pane (thought bubble)", then click build, and expand the build lines to see what clang was passed.

  • pmhart83pmhart83 USMember ✭✭✭

    I did have an Xcode project. Here is what I am seeing in the section you mentioned:

    clang -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -L/Users/Paul/Library/Developer/Xcode/DerivedData/AppStoreReceipt-cogqxtnqhvabmlfrmweqndbywcxl/Build/Products/Debug -F/Users/Paul/Library/Developer/Xcode/DerivedData/AppStoreReceipt-cogqxtnqhvabmlfrmweqndbywcxl/Build/Products/Debug -filelist /Users/Paul/Library/Developer/Xcode/DerivedData/AppStoreReceipt-cogqxtnqhvabmlfrmweqndbywcxl/Build/Intermediates/AppStoreReceipt.build/Debug/AppStoreReceipt.build/Objects-normal/x86_64/AppStoreReceipt.LinkFileList -Xlinker -rpath -Xlinker @executable_path/../Frameworks -mmacosx-version-min=10.10 -fobjc-arc -fobjc-link-runtime -Xlinker -dependency_info -Xlinker /Users/Paul/Library/Developer/Xcode/DerivedData/AppStoreReceipt-cogqxtnqhvabmlfrmweqndbywcxl/Build/Intermediates/AppStoreReceipt.build/Debug/AppStoreReceipt.build/Objects-normal/x86_64/AppStoreReceipt_dependency_info.dat -o /Users/Paul/Library/Developer/Xcode/DerivedData/AppStoreReceipt-cogqxtnqhvabmlfrmweqndbywcxl/Build/Products/Debug/AppStoreReceipt.app/Contents/MacOS/AppStoreReceipt

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    Hmm. Did you check the link step? They are calling clang a few time, for the o files and then the link.

    I see -framework Security

  • pmhart83pmhart83 USMember ✭✭✭

    Yes, that was from the link step. I finally got it, was a matter of figuring out the command line syntax. I was trying to do it with a pipe, but you just need to repeat -framework:

    clang -dynamiclib -arch x86_64 -mmacosx-version-min=10.10 -std=gnu99 RVNReceiptValidation.m -current_version 1.0 -compatibility_version 1.0 -fvisibility=hidden -framework Security -framework Cocoa -framework IOKit -o bin/RVNReceiptValidation.dylib

    I now have a dylib file! Lets see how much further I can get haha. Thanks.

  • pmhart83pmhart83 USMember ✭✭✭
    edited September 2015

    @ChrisHamons

    I am now able to create a .dll file for this. I am so close! Yet when I create an instance using:
    RVNReceiptValidation v = new RVNReceiptValidation();

    The app quits saying:
    Debugger operation failed
    Argument cannot be null
    Paramter name: attributeType

    Here is some of the code included in my .dll:

    @interface RVNReceiptValidation : NSObject

    bool ValidateAppStoreReceipt();

    @end

    RNVRecepitValidation.m (note this is the exact same as git hub except I created this function)

    bool ValidateAppStoreReceipt()
    {

    BOOL isSuccess = YES;
    
    @try {
    
        ///// Check the bundle information
        RVNCheckBundleIDAndVersion();
        RVNCheckBundleSignature();
    
        ///// Check the receipt information
        NSData *receiptData = RVNGetReceiptData();
        NSData *receiptDataDecoded = RVNDecodeReceiptData(receiptData);
        NSDictionary *receiptInfo = RVNGetReceiptPayload(receiptDataDecoded);
    
        RVNCheckReceiptIDAndVersion(receiptInfo);
        RVNCheckReceiptHash(receiptInfo);
    
    } @catch (NSException *e) {
    
        NSLog(@"%@", e.reason);
        isSuccess = NO;
    
    }
    
    return isSuccess;
    

    }

    RVNReceiptValidation.cs:

    using Foundation;

    namespace Musicnotes.Mac {

    [BaseType (typeof (NSObject))]
    interface RVNReceiptValidation {

    [Export ("ValidateAppStoreReceipt")]
    bool ValidateAppStoreReceipt();
    

    }

    }

    I am getting lost somewhere having to create an instance of the object vs having a static function. I will need to read up on binding a static C function.

    Note, sorry the code thing in this forum doesn't look right.

  • pmhart83pmhart83 USMember ✭✭✭

    Using the make file to determine if I got this working or not, I am very close but just missing something:

    $ make
    mkdir -p bin tmp
    clang -dynamiclib -arch x86_64 -std=gnu99 RVNReceiptValidation.m -current_version 1.0 -compatibility_version 1.0 -fvisibility=hidden -framework Security -framework Cocoa -framework IOKit -o bin/RVNReceiptValidation.dylib
    MONO_PATH=/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/bin/bmac-mobile-mono /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/bmac/bmac-mobile.exe -baselib:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/reference/mobile/Xamarin.Mac.dll --api=RVNReceiptValidation.cs -o:bin/RVNReceiptValidation.dll --tmpdir=tmp --ns=Musicnotes.Mac
    WARNING: The runtime version supported by this application is unavailable.
    Using default runtime: v4.0.30319
    mcs /out:bin/RVNReceiptValidationTest.exe RVNReceiptValidationTest.cs /target:exe /nostdlib /reference:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/System.dll /reference:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/System.Core.dll /reference:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/Xamarin.Mac.dll /reference:bin/RVNReceiptValidation.dll /reference:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/mscorlib.dll
    RVNReceiptValidationTest.cs(23,8): warning CS0219: The variable `v' is assigned but its value is never used
    Compilation succeeded - 1 warning(s)
    /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/bin/mmp /output:bin /name:RVNReceiptValidationTest /profile:Xamarin.Mac /arch:x86_64 /sgen /new-refcount /nolink /assembly:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/System.dll /assembly:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/System.Core.dll /assembly:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/Xamarin.Mac.dll /assembly:bin/RVNReceiptValidation.dll /assembly:/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/Xamarin.Mac/mscorlib.dll bin/RVNReceiptValidationTest.exe
    Xamarin.Mac 2.0.1 Business Edition
    warning MM2006: Native library 'liboleaut32.dylib' was referenced but could not be found.
    bundling complete
    cp bin/RVNReceiptValidation.dylib bin/RVNReceiptValidationTest.app/Contents/MonoBundle/
    ./bin/RVNReceiptValidationTest.app/Contents/MacOS/RVNReceiptValidationTest
    Xamarin.Mac: Could not load machine.config: /Users/Paul/Downloads/XMBindingExample/bin/RVNReceiptValidationTest.app/Contents/MonoBundle/machine.config
    WARNING: The runtime version supported by this application is unavailable.
    Using default runtime: v4.0.30319
    ObjCRuntime.Dlfcn.dlopen (/Users/Paul/Downloads/XMBindingExample/bin/RVNReceiptValidationTest.app/Contents/MonoBundle/RVNReceiptValidation.dylib)

    Unhandled Exception:
    System.Exception: Could not create an native instance of the type 'Musicnotes.Mac.RVNReceiptValidation': the native class hasn't been loaded.
    It is possible to ignore this condition by setting ObjCRuntime.Class.ThrowOnInitFailure to false.
    at Foundation.NSObject.InitializeObject (Boolean alloced) [0x00000] in :0
    at Foundation.NSObject..ctor (Foundation.NSObjectFlag x) [0x00000] in :0
    at Musicnotes.Mac.RVNReceiptValidation..ctor () [0x00000] in :0
    at Musicnotes.Mac.MainClass.Main (System.String[] args) [0x00000] in :0
    [ERROR] FATAL UNHANDLED EXCEPTION: System.Exception: Could not create an native instance of the type 'Musicnotes.Mac.RVNReceiptValidation': the native class hasn't been loaded.
    It is possible to ignore this condition by setting ObjCRuntime.Class.ThrowOnInitFailure to false.
    at Foundation.NSObject.InitializeObject (Boolean alloced) [0x00000] in :0
    at Foundation.NSObject..ctor (Foundation.NSObjectFlag x) [0x00000] in :0
    at Musicnotes.Mac.RVNReceiptValidation..ctor () [0x00000] in :0
    at Musicnotes.Mac.MainClass.Main (System.String[] args) [0x00000] in :0
    make: *** [all] Error 1

    I am curious about:
    warning MM2006: Native library 'liboleaut32.dylib' was referenced but could not be found.

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    Are you loading the native library before NSApplication.Init (). Aka the ObjCRuntime.Dlfcn.dlopen dance?

  • pmhart83pmhart83 USMember ✭✭✭

    Here is my "test" code:

    `using System;
    using System.Reflection;
    using System.IO;
    using AppKit;

    namespace Musicnotes.Mac
    {
    static class MainClass
    {

        // http://stackoverflow.com/questions/52797/how-do-i-get-the-path-of-the-assembly-the-code-is-in
        public static string GetCurrentExecutingDirectory()
        {
            string filePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath;
            return Path.GetDirectoryName(filePath);
        }
    
        static void Main (string[] args)
        {
    
            string path = GetCurrentExecutingDirectory () + "/RVNReceiptValidation.dylib";
            Console.WriteLine("ObjCRuntime.Dlfcn.dlopen ({0})", path);
            var v = ObjCRuntime.Dlfcn.dlopen (path, 0);
    
            NSApplication.Init ();
    
            RVNReceiptValidation c = new RVNReceiptValidation ();
            c.ValidateAppStoreReceipt();
    
        }
    
    }
    

    }`

  • pmhart83pmhart83 USMember ✭✭✭

    OK, so after more digging around and comparing to example. I finally got the make file to work!!!

    It was because I needed to use @implement RVNReceiptValidation around my instance code. Makes perfect since.

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    Could you consider packaging up your example for others to use? As you pointed out, you aren't the first or the last to run into this pain point.

  • pmhart83pmhart83 USMember ✭✭✭

    @ChrisHamons

    Hopefully the last thing I will bug you about on this. I included the DLL created by my make file in Xamarin (note the make file executes a test which I see the code is being run), but I am still seeing:

    Debugger operation failed
    Argument cannot be null.
    Parameter name: attributeType

  • pmhart83pmhart83 USMember ✭✭✭
    edited September 2015

    Sure, I am still not done yet ... At the end of the article you showed me, it states:

    To use this binding in another Xamarin.Mac application, make a Reference to the SimpleClass.dll file that was created in the bin directory. Again, you'll need to moves the Dylib into the Xamarin.Mac application's bundle. This would typically be done by Xamarin Studio automatically when you include the SimpleClass.dll in a project.

    I am not seeing the dylib in the .app file.

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai
    edited September 2015

    Unlike Xamarin.iOS, we don't have baked in support for binding projects / native references. I'm not sure what the article is referencing to be honest.

    Right now, you need to make a post-build step to copy the dylib into your app bundle.

    • Right click project
    • Custom Commands
    • After build in dropdown

    We are working on improving the integration with native libraries / bindings in a future version, so it will be closer to how things are with Xamarin.iOS.

  • pmhart83pmhart83 USMember ✭✭✭

    I finally got it by manually copying the dylib!!!! Oh man this was complex. Thanks for your help. I will come up with a way to copy the dylib with your suggestion.

    I will create a github with my solution.

  • pmhart83pmhart83 USMember ✭✭✭
    edited September 2015

    @ChrisHamons

    Here is the solution you had asked for on my github:
    https://github.com/pmhart83/xamarin-mac-RVNReceiptValidation-binding

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    Good stuff. Thanks for packaging everything up for others!

  • KMullinsKMullins USMember, Xamarin Team Xamurai

    All,

    Sorry for the late response, I've been tied up documenting iOS 9 support. I'll add this to the list of Xamarin.Mac documentation requests and see if I can get @pmhart83's solution included in the docs/samples here shortly.

    Please let me know if you need anything else.

    Thanks,

    Kevin

  • BobMilanovBobMilanov BGMember

    Hi Chris,

    I'm trying to build the same but got stuck on the part where I need to copy the dylib in the package - what exactly am I supposed to type in post build so that it gets copied to the correct path in the package?

  • BobMilanovBobMilanov BGMember

    Another issue - when you actually create the example for the app purchase you may consider to sign the ReceiptValidation.dll as it cannot be used in signed .exe currently.

  • pmhart83pmhart83 USMember ✭✭✭
    edited September 2015

    I ran into problems with our first submission. The dll / dylib have to be read only.

    I solved the issue of the dylib not being in the bundle folder by moving it from resources to monobundle using System.IO.

    You can include a reference to the dll but it will not work until you copy the dylib to MonoBundle.

    Also I had to change the original code by moving the static NSString config vars to an instance var then pass the receipt object to the static functions and see what the instance of bundleId is. Somehow it was crashing when included in the mac project otherwise.

  • ChrisHamonsChrisHamons USForum Administrator, Xamarin Team Xamurai

    @BobMilanov You'll need to create a Custom Command / Post build that copies you file into the right directory.

    You can play around with the various environmental variables by doing things like:

    echo ${TargetDir}

    and building.

    Roughly, it'll be something like cp ${ProjectDir}/WHEREVER_YOU_KEEP_THE_DYLIB ${TargetDir}/Foo.app/Contents/MonoBundle/

  • BobMilanovBobMilanov BGMember

    Thanks Chris,

    Managed to get past this step but the problem with the signing remained (could not find a switch to sign the generated dll) so I switched to fully managed code to check the receipt that does not use cryptography - hopefully that will get me through the app review :). In case somebody else bumps into this it is important to call NSApplication.Init(), before accessing the NSBundle.MainBundle.AppStoreReceiptUrl property - otherwise the app simply crashes. In case the receipt verification fails simply exit with Environment.Exit(173);. When I finish the whole code I'll post it in the forum as well...

  • AmySAmyS USMember

    @KMullins Hi Kevin, from apple's documentation. there shouldn't be much difference validating receipts between mac ox and iOS. Do you think this method discussed in this thread can be applied to iOS app? i.e. Package RVNReceiptValidation into static library then import it in Xamarin.iOS project?

    thanks,
    Amy

Sign In or Register to comment.