4

I have a pretty massive iOS Framework to bind. This framework depends on two others.

I created the binding project, successfully generated the ApiDefinitions.cs file and StructsAndEnums.cs. So far so good.

Now, when I try to build it in Debug mode, I get about 30+ errors regarding syntax issues in temporary files.

These errors only occur in Trampolines.g.cs, and SupportDelegates.g.cs files. The worst of the two is the SupportDelegates.g.cs file which looks like this :

   //
// Auto-generated from generator.cs, do not edit
//
// We keep references to objects, so warning 414 is expected

#pragma warning disable 414

using System;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using UIKit;
using GLKit;
using Metal;
using MapKit;
using Photos;
using ModelIO;
using SceneKit;
using Contacts;
using Security;
using Messages;
using AudioUnit;
using CoreVideo;
using CoreMedia;
using QuickLook;
using CoreImage;
using SpriteKit;
using Foundation;
using CoreMotion;
using ObjCRuntime;
using AddressBook;
using MediaPlayer;
using GameplayKit;
using CoreGraphics;
using CoreLocation;
using AVFoundation;
using NewsstandKit;
using FileProvider;
using CoreAnimation;
using CoreFoundation;

namespace System.Action`1[[Foundation.NSString, Xamarin.iOS, Version=0.0.0 {
    public delegate void 0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065]] (NSString obj);
}

The Trampolines.g.cs file is generating almost completely, but the same kind of issue appears in the middle of the generated C# code:

static internal class SDActionArity2V1 {
            static internal readonly DActionArity2V1 Handler = Invoke;

            [MonoPInvokeCallback (typeof (DActionArity2V1))]
            static unsafe void Invoke (IntPtr block, IntPtr arg1, IntPtr arg2) {
                var descriptor = (BlockLiteral *) block;
                var del = (global::System.Action<NSString, global::System.Action<NSString>>) (descriptor->Target);
                if (del != null)
                    del ( Runtime.GetNSObject<NSString> (arg1), (System.Action`1[Foundation.NSString]) Marshal.GetDelegateForFunctionPointer (arg2, typeof (System.Action`1[Foundation.NSString])));
            }
        }

Some other binding projects is generating the same kind of files, and eveything seems to be working fine, so I'm actually struggling to find the root cause of this.

Any ideas ?

EDIT: To give more infos here is the generated interface definition https://gist.github.com/Miiite/367e17335431e932acdc92c65b504bd4

EDIT2: Here is what sharpie generated as log output https://gist.github.com/Miiite/e272622df2e853d53f1add4c8eb4eabf

Miiite
  • 1,517
  • 10
  • 16
  • Have you checked your ApiDefinition.cs for [verify] attributes? A good guide: [Xamarin Binding Objective-C](https://developer.xamarin.com/guides/ios/advanced_topics/binding_objective-c/walkthrough/) – tequila slammer Mar 01 '18 at 19:16
  • Something wrong seems happened when using sharpie. Can you attach the error message in the Terminal.. – ColeX Mar 02 '18 at 07:10
  • @ColeXia-MSFT I added sharpie's logs in the post, as well as the generated APIDefinitions.cs (after I checked the [Verify] attributes (I only had 2 in them). Checking these attributes were done in the first place. So it's not what is preventing me from building – Miiite Mar 02 '18 at 07:53
  • Well ,What's the version of the sharpie , please make sure it is up to date.and if the framework has been registered in cocospod , I suggest you to use [this](https://developer.xamarin.com/guides/cross-platform/macios/binding/objective-sharpie/examples/cocoapod/). – ColeX Mar 02 '18 at 08:09
  • I'm on the latest version (I always run sharpie update before doing anything). But unfortunately it's not available as a cocoapod (it's a private Framework) – Miiite Mar 02 '18 at 11:07
  • @Miiite I would post it as an issue : https://github.com/xamarin/xamarin-macios/issues – SushiHangover Mar 03 '18 at 17:19

2 Answers2

6

I believe the issue is here: void PresentCheckoutForSubmittingTransactionCompletionHandler(Action<OPPTransaction, NSError> completionHandler, [NullAllowed] Action<NSString, Action<NSString>> paymentBrandSelectedHandler, [NullAllowed] Action cancelHandler);

I think the Action inside the Action is causing the problem, the generator might not support this, so you might need to find a different way of binding that.

miguel.de.icaza
  • 32,654
  • 6
  • 58
  • 76
  • I'll check this part as soon as possible :) – Miiite Mar 07 '18 at 13:45
  • That was it ! Now I have to understand why this was considered by sharpie as the Objective-C equivalent. Thanks again Miguel :) – Miiite Mar 07 '18 at 16:58
  • 1
    @Miiite This was considered by sharpie like that because it is kind of correct, `Action` is a shortcut to not explicitly declare a custom `delegate` but our generator does not currently support the nested `Action`s so it outputs invalid code. I'll have a look into giving a better error instead of just outputting invalid code. – dalexsoto Mar 18 '18 at 04:54
3

This problematic method can definitely be bound, if you need it here is how (I omitted the rest of the class members for brevity):

delegate void OPPPaymentBrandSelectedHandler (string paymentBrand, [BlockCallback] OPPPaymentCompletionHandler completionHandler);
delegate void OPPPaymentCompletionHandler ([NullAllowed] string checkoutId);

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

    // -(void)presentCheckoutForSubmittingTransactionCompletionHandler:(void (^ _Nonnull)(OPPTransaction * _Nullable, NSError * _Nullable))completionHandler
    // paymentBrandSelectedHandler:(void (^ _Nullable)(NSString * _Nonnull, void (^ _Nonnull)(NSString * _Nullable)))paymentBrandSelectedHandler 
    // cancelHandler:(void (^ _Nullable)(void))cancelHandler;
    [Export("presentCheckoutForSubmittingTransactionCompletionHandler:paymentBrandSelectedHandler:cancelHandler:")]
    void PresentCheckoutForSubmittingTransactionCompletionHandler(Action<OPPTransaction, NSError> completionHandler, [NullAllowed] OPPPaymentBrandSelectedHandler paymentBrandSelectedHandler, [NullAllowed] Action cancelHandler);
}

The trick is to instead of using nested Actions you need to break it into two delegates and use the BlockCallback attribute to instruct the generator that the parameter should be marshaled as an ObjC block, then just use the parent delegate as the type of the paymentBrandSelectedHandler parameter inside the PresentCheckoutForSubmittingTransactionCompletionHandler method.

Hope this helps to get you completely unblocked. That said we should report a much better error, I'll discuss with the team and have a look.

Cheers!

dalexsoto
  • 3,412
  • 1
  • 27
  • 43
  • Great workaround indeed. Looks so simple when you have the solution right under your nose. Thanks again for this – Miiite Mar 19 '18 at 08:08