intercom / intercom-dotnet

Intercom API client library for .NET
https://developers.intercom.io/reference
Apache License 2.0
63 stars 53 forks source link

Update SDK to dotnet Standard 2.0 #97

Closed kmossco closed 6 years ago

kmossco commented 6 years ago

Changelog:

Bugfixes:

I have left this as multiple commits in case we need to revert quickly. This should make it easier.

Note: I didn't move the library to async and removed the dependency on RestSharp because after exploring the work done by @michael-watson I wasn't confident that our current test coverage could protect us from any unintended consequences.

And once again, thank you so much for the time and effort you put into this library to both @Nicholi and @michael-watson. If you could drop me an email at bruno+dotnet[at]intercom[dot]io I'd love to discuss with you how we can improve the visibility of the work you put into it. 👍

choran commented 6 years ago

Wow, just general call out on the readme changes alone, think there is lots more helpful detail and examples here and even the presentation changes are great Working my way through it now but just wanted to call that out already

NPSF3000 commented 6 years ago

Hi guys, any word on the status of this? We're moving our entire project to net core and this is one of the few blocking libraries left.

mbrookson commented 6 years ago

Hi, will this library only work with Xamarin iOS and Android once this migration to .NET Standard is resolved?

kmossco commented 6 years ago

@NPSF3000 so sorry for the delay in getting this out of the door. Just in case you aren't following the issue #90: the reason behind this delay is that we unfortunately hit a snag creating the Nuget package in a way that it doesn't break plenty of apps that don't want to upgrade the library, and we are working to create a new release. We should have an update very soon though!

kmossco commented 6 years ago

@mbrookson this will work with any project compatible with .NET Standard 2.0. We don't have any support for Xamarin bindings though, and don't really have it yet in our near future roadmap.

michael-watson commented 6 years ago

To add details, this library will work in any Xamarin project, you just won't have the UI controls that are currently provided in their native SDKs. The options are porting that code to C# (currently not open-source so no go there) or binding the iOS/Android libraries.

For anyone out there that is interested, I ran the iOS cocoapod through Objective Sharpie and got the output for the ios bindings. For Android, you would need the library as a jar or aar and then bind that. Typically Android libraries are much easier. The iOS portion you could just download the framework manually, build it and reference that in the Xamarin.iOS project. I have not tested any of the library bindings, so if something doesn't work, check they binding type reference for that method and fix whatever difference there is.

@kmossco If the source code for the iOS and Android portions of the messengers (iOS Controllers/Delegates and Android xaml/Activities/Adapters) were open sourced, it wouldn't take much to translate that directly to Xamarin C#. I have an upcoming project that would be great if I could use Intercom inside of the mobile application, but having to build the binding library process typically is a deal breaker for most developers. Feel free to PM me if you have interest in collaborating on the possibilities here.

iOS Binding Outputs

C# ApiDefinition

using System;
using Foundation;
//using Intercom;
using ObjCRuntime;

namespace intercom.binding.ios
{
    // @interface ICMCompany : NSObject
    [BaseType(typeof(NSObject))]
    interface ICMCompany
    {
        // @property (copy, nonatomic) NSString * _Nullable companyId;
        [NullAllowed, Export("companyId")]
        string CompanyId { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable name;
        [NullAllowed, Export("name")]
        string Name { get; set; }

        // @property (nonatomic, strong) NSDate * _Nullable createdAt;
        [NullAllowed, Export("createdAt", ArgumentSemantic.Strong)]
        NSDate CreatedAt { get; set; }

        // @property (nonatomic, strong) NSNumber * _Nullable monthlySpend;
        [NullAllowed, Export("monthlySpend", ArgumentSemantic.Strong)]
        NSNumber MonthlySpend { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable plan;
        [NullAllowed, Export("plan")]
        string Plan { get; set; }

        // @property (nonatomic, strong) NSDictionary<NSString *,id> * _Nullable customAttributes;
        [NullAllowed, Export("customAttributes", ArgumentSemantic.Strong)]
        NSDictionary<NSString, NSObject> CustomAttributes { get; set; }

        // +(NSString * _Nonnull)nullStringAttribute;
        [Static]
        [Export("nullStringAttribute")]
        //[Verify(MethodToProperty)]
        string NullStringAttribute { get; }

        // +(NSNumber * _Nonnull)nullNumberAttribute;
        [Static]
        [Export("nullNumberAttribute")]
        //[Verify(MethodToProperty)]
        NSNumber NullNumberAttribute { get; }

        // +(NSDate * _Nonnull)nullDateAttribute;
        [Static]
        [Export("nullDateAttribute")]
        //[Verify(MethodToProperty)]
        NSDate NullDateAttribute { get; }

        // -(NSDictionary<NSString *,id> * _Nonnull)attributes;
        [Export("attributes")]
        //[Verify(MethodToProperty)]
        NSDictionary<NSString, NSObject> Attributes { get; }
    }

    // @interface ICMUserAttributes : NSObject
    [BaseType(typeof(NSObject))]
    interface ICMUserAttributes
    {
        // @property (copy, nonatomic) NSString * _Nullable email;
        [NullAllowed, Export("email")]
        string Email { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable userId;
        [NullAllowed, Export("userId")]
        string UserId { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable name;
        [NullAllowed, Export("name")]
        string Name { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable phone;
        [NullAllowed, Export("phone")]
        string Phone { get; set; }

        // @property (copy, nonatomic) NSString * _Nullable languageOverride;
        [NullAllowed, Export("languageOverride")]
        string LanguageOverride { get; set; }

        // @property (nonatomic, strong) NSDate * _Nullable signedUpAt;
        [NullAllowed, Export("signedUpAt", ArgumentSemantic.Strong)]
        NSDate SignedUpAt { get; set; }

        // @property (assign, nonatomic) BOOL unsubscribedFromEmails;
        [Export("unsubscribedFromEmails")]
        bool UnsubscribedFromEmails { get; set; }

        // @property (nonatomic, strong) NSArray<ICMCompany *> * _Nullable companies;
        [NullAllowed, Export("companies", ArgumentSemantic.Strong)]
        ICMCompany[] Companies { get; set; }

        // @property (nonatomic, strong) NSDictionary<NSString *,id> * _Nullable customAttributes;
        [NullAllowed, Export("customAttributes", ArgumentSemantic.Strong)]
        NSDictionary<NSString, NSObject> CustomAttributes { get; set; }

        // +(NSString * _Nonnull)nullStringAttribute;
        [Static]
        [Export("nullStringAttribute")]
        //[Verify(MethodToProperty)]
        string NullStringAttribute { get; }

        // +(NSNumber * _Nonnull)nullNumberAttribute;
        [Static]
        [Export("nullNumberAttribute")]
        //[Verify(MethodToProperty)]
        NSNumber NullNumberAttribute { get; }

        // +(NSDate * _Nonnull)nullDateAttribute;
        [Static]
        [Export("nullDateAttribute")]
        //[Verify(MethodToProperty)]
        NSDate NullDateAttribute { get; }

        // -(NSDictionary<NSString *,id> * _Nonnull)attributes;
        [Export("attributes")]
        //[Verify(MethodToProperty)]
        NSDictionary<NSString, NSObject> Attributes { get; }
    }

    // @interface Intercom : NSObject
    [BaseType(typeof(NSObject))]
    interface Intercom
    {
        // +(void)setApiKey:(NSString * _Nonnull)apiKey forAppId:(NSString * _Nonnull)appId;
        [Static]
        [Export("setApiKey:forAppId:")]
        void SetApiKey(string apiKey, string appId);

        // +(void)setUserHash:(NSString * _Nonnull)userHash;
        [Static]
        [Export("setUserHash:")]
        void SetUserHash(string userHash);

        // +(void)registerUnidentifiedUser;
        [Static]
        [Export("registerUnidentifiedUser")]
        void RegisterUnidentifiedUser();

        // +(void)registerUserWithUserId:(NSString * _Nonnull)userId email:(NSString * _Nonnull)email;
        [Static]
        [Export("registerUserWithUserId:email:")]
        void RegisterUserWithUserId(string userId, string email);

        // +(void)registerUserWithUserId:(NSString * _Nonnull)userId;
        [Static]
        [Export("registerUserWithUserId:")]
        void RegisterUserWithUserId(string userId);

        // +(void)registerUserWithEmail:(NSString * _Nonnull)email;
        [Static]
        [Export("registerUserWithEmail:")]
        void RegisterUserWithEmail(string email);

        // +(void)logout;
        [Static]
        [Export("logout")]
        void Logout();

        // +(void)reset __attribute__((deprecated("'+[Intercom reset]' is deprecated. 'Use +[Intercom logout]' instead.")));
        [Static]
        [Export("reset")]
        void Reset();

        // +(void)updateUser:(ICMUserAttributes * _Nonnull)userAttributes;
        [Static]
        [Export("updateUser:")]
        void UpdateUser(ICMUserAttributes userAttributes);

        // +(void)logEventWithName:(NSString * _Nonnull)name;
        [Static]
        [Export("logEventWithName:")]
        void LogEventWithName(string name);

        // +(void)logEventWithName:(NSString * _Nonnull)name metaData:(NSDictionary * _Nonnull)metaData;
        [Static]
        [Export("logEventWithName:metaData:")]
        void LogEventWithName(string name, NSDictionary metaData);

        // +(void)presentMessenger;
        [Static]
        [Export("presentMessenger")]
        void PresentMessenger();

        // +(void)presentMessageComposer;
        [Static]
        [Export("presentMessageComposer")]
        void PresentMessageComposer();

        // +(void)presentMessageComposerWithInitialMessage:(NSString * _Nonnull)message;
        [Static]
        [Export("presentMessageComposerWithInitialMessage:")]
        void PresentMessageComposerWithInitialMessage(string message);

        // +(void)presentConversationList;
        [Static]
        [Export("presentConversationList")]
        void PresentConversationList();

        // +(void)presentHelpCenter;
        [Static]
        [Export("presentHelpCenter")]
        void PresentHelpCenter();

        // +(void)setDeviceToken:(NSData * _Nonnull)deviceToken;
        [Static]
        [Export("setDeviceToken:")]
        void SetDeviceToken(NSData deviceToken);

        // +(BOOL)isIntercomPushNotification:(NSDictionary * _Nonnull)userInfo;
        [Static]
        [Export("isIntercomPushNotification:")]
        bool IsIntercomPushNotification(NSDictionary userInfo);

        // +(void)handleIntercomPushNotification:(NSDictionary * _Nonnull)userInfo;
        [Static]
        [Export("handleIntercomPushNotification:")]
        void HandleIntercomPushNotification(NSDictionary userInfo);

        // +(void)setBottomPadding:(CGFloat)bottomPadding;
        [Static]
        [Export("setBottomPadding:")]
        void SetBottomPadding(nfloat bottomPadding);

        // +(void)setInAppMessagesVisible:(BOOL)visible;
        [Static]
        [Export("setInAppMessagesVisible:")]
        void SetInAppMessagesVisible(bool visible);

        // +(void)setLauncherVisible:(BOOL)visible;
        [Static]
        [Export("setLauncherVisible:")]
        void SetLauncherVisible(bool visible);

        // +(void)hideMessenger;
        [Static]
        [Export("hideMessenger")]
        void HideMessenger();

        // +(NSUInteger)unreadConversationCount;
        [Static]
        [Export("unreadConversationCount")]
        //[Verify(MethodToProperty)]
        nuint UnreadConversationCount { get; }

        // +(void)enableLogging;
        [Static]
        [Export("enableLogging")]
        void EnableLogging();

        // +(void)setNeedsStatusBarAppearanceUpdate;
        [Static]
        [Export("setNeedsStatusBarAppearanceUpdate")]
        void SetNeedsStatusBarAppearanceUpdate();
    }

    [Static]
    //[Verify(ConstantsInterfaceAssociation)]
    partial interface Constants
    {
        // extern NSString *const _Nonnull IntercomUnreadConversationCountDidChangeNotification __attribute__((visibility("default")));
        [Field("IntercomUnreadConversationCountDidChangeNotification", "__Internal")]
        NSString IntercomUnreadConversationCountDidChangeNotification { get; }

        // extern NSString *const _Nonnull IntercomWindowWillShowNotification __attribute__((visibility("default")));
        [Field("IntercomWindowWillShowNotification", "__Internal")]
        NSString IntercomWindowWillShowNotification { get; }

        // extern NSString *const _Nonnull IntercomWindowDidShowNotification __attribute__((visibility("default")));
        [Field("IntercomWindowDidShowNotification", "__Internal")]
        NSString IntercomWindowDidShowNotification { get; }

        // extern NSString *const _Nonnull IntercomWindowWillHideNotification __attribute__((visibility("default")));
        [Field("IntercomWindowWillHideNotification", "__Internal")]
        NSString IntercomWindowWillHideNotification { get; }

        // extern NSString *const _Nonnull IntercomWindowDidHideNotification __attribute__((visibility("default")));
        [Field("IntercomWindowDidHideNotification", "__Internal")]
        NSString IntercomWindowDidHideNotification { get; }

        // extern NSString *const _Nonnull IntercomDidStartNewConversationNotification __attribute__((visibility("default")));
        [Field("IntercomDidStartNewConversationNotification", "__Internal")]
        NSString IntercomDidStartNewConversationNotification { get; }
    }

    // @interface Experimental (Intercom)
    [Category]
    [BaseType(typeof(Intercom))]
    interface Intercom_Experimental
    {
    }
}

StructsEnums

[Native]
public enum ICMPreviewPosition : uint
{
    BottomLeft = 0,
    BottomRight = 1,
    TopLeft = 2,
    TopRight = 3
}
kmossco commented 6 years ago

@michael-watson that's awesome, thank you so much for sharing! We currently don't have any plans for open sourcing those libraries, but I'll reach out to the team anyway and present this message to see if there's anything we can do. In the mean time, we currently have de-scoped working on Xamarin bindings in this library so that we can focus on first bringing it to .NET Standard 2.0 and then ensure feature parity with our REST API features. When that's done, I think we can then look into it for sure. 😉