3

I want to develop Salesforce chatbot with xamarin forms application. I am not able to find what sdk or nuget package, I should use. There is no information seem to available regarding this.

This salesforce article, I have found, where they do it for Android and iOS.

I have tried it by using .jar files of android libraries but that doesn't work, for that iOS development also required separately. I have found this article but not sure what package and which platform they are developing.

How to do Salesforce Einstein Chatbot integration with Xamarin forms. Can anyone please help me regarding this?

R15
  • 13,982
  • 14
  • 97
  • 173
  • https://developer.salesforce.com/docs/atlas.en-us.bot_cookbook.meta/bot_cookbook/bot_cookbook_mobile_section.htm – Jason Mar 09 '22 at 19:04
  • @Jason - Thank you. In that link they are using `com.salesforce.service:chat-ui:4.3.2` and `https://s3.amazonaws.com/salesforcesos.com/android/maven/release` packages with android. In VS2019 nuget, I can find `Developer.Force.Chatter`. Can I use this package with xamarin forms ? – R15 Mar 09 '22 at 19:19
  • you would need to create Xamarin binding libraries for iOS and Android. I have no idea if there is a similar library for .NET – Jason Mar 09 '22 at 20:16
  • @Jason - Can you please guide me, how to get `.jar` files for above libraries as given in article share by you. – R15 Mar 10 '22 at 16:22
  • I have no idea. Download them and examine them to find where the jar files are, I'd guess – Jason Mar 10 '22 at 16:28
  • https://stackoverflow.com/questions/44567113/consume-jar-from-net-core hope this answer from domusmagister may help – SDHEER Mar 18 '22 at 07:20
  • @SDHEER - I followed same approach, please check `edit 1` in this question, to see what problem I am facing https://stackoverflow.com/questions/71441631/is-there-any-way-to-get-jar-files-of-android-library-with-all-dependencies-using – R15 Mar 18 '22 at 14:18

1 Answers1

2

Jar files, nuget packages doesn't work for me. I have just used webview with custom renderer. This is how I managed to integrate Salesforce chatbot

public class SfChatbotViewModel : BaseViewModel
{
    public SfChatbotViewModel()
    {

    }
}  
<controls:HybridWebView Margin="0" x:Name="webView"
    VerticalOptions="FillAndExpand"
    HorizontalOptions="FillAndExpand" />

This is HybridWebView Webview control in Shared(common) project

    public class HybridWebView : Xamarin.Forms.WebView
    {
        Action<string> action;
        public static readonly BindableProperty UriProperty = BindableProperty.Create(
            propertyName: "Uri",
            returnType: typeof(string),
            declaringType: typeof(HybridWebView),
            defaultValue: default(string));
        public string Uri
        {
            get { return (string)GetValue(UriProperty); }
            set { SetValue(UriProperty, value); }
        }
        public void RegisterAction(Action<string> callback)
        {
            action = callback;
        }
        public void Cleanup()
        {
            action = null;
        }
        public void InvokeAction(string data)
        {
            if (action == null || data == null)
            {
                return;
            }
            action.Invoke(data);
        }
    }
Below `Webview renderer` in Android project

    public class HybridWebViewRenderer : WebViewRenderer
    {
        const string JavascriptFunction = "function initESW(data){jsBridge.invokeAction(data);}";
        Context _context;
        public HybridWebViewRenderer(Context context) : base(context)
        {
            _context = context;
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);
            global::Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
            if (e.OldElement != null)
            {
                Control.RemoveJavascriptInterface("jsBridge");
                ((HybridWebView)Element).Cleanup();
            }
            if (e.NewElement != null)
            {
                CookieManager.Instance.SetAcceptCookie(true);
                CookieManager.Instance.SetAcceptThirdPartyCookies(Control, true);
                Control.SetWebViewClient(new JavascriptWebViewClient(this, $"javascript: {JavascriptFunction}"));
                Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
                Control.Settings.AllowFileAccess = true;
                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.AllowFileAccessFromFileURLs = true;
                Control.Settings.AllowUniversalAccessFromFileURLs = true;
                Control.Settings.AllowContentAccess = true;
                Control.Settings.DomStorageEnabled = true;
                Control.SetWebChromeClient(new WebChromeClient());
    
                var content_UAT = LoadData("ChatUAT.html");
    
                Control.LoadDataWithBaseURL("https://service.force.com/embeddedservice/5.0/esw.min.js",
                    content_UAT,
                    "text/html;",
                    null,
                    "https://service.force.com/embeddedservice/5.0/esw.min.js");
            }
        }
        public class JavascriptWebViewClient : FormsWebViewClient
        {
            string _javascript;
            public JavascriptWebViewClient(HybridWebViewRenderer renderer, string javascript) : base(renderer)
            {
                _javascript = javascript;
            }
            public override void OnPageFinished(Android.Webkit.WebView view, string url)
            {
                base.OnPageFinished(view, url);
                view.EvaluateJavascript("document.cookie", null);
            }
            public override void OnReceivedSslError(Android.Webkit.WebView view, SslErrorHandler handler, SslError error)
            {
                Console.WriteLine("Salesforce webview error: ", error);
                base.OnReceivedSslError(view, handler, error);
            }
            public override void OnReceivedHttpError(Android.Webkit.WebView view, IWebResourceRequest request, WebResourceResponse errorResponse)
            {
                base.OnReceivedHttpError(view, request, errorResponse);
            }
            public override void OnLoadResource(Android.Webkit.WebView view, string url)
            {
                base.OnLoadResource(view, url);
            }
        }
        public class JSBridge : Java.Lang.Object
        {
            readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;
            public JSBridge(HybridWebViewRenderer hybridRenderer)
            {
                hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
            }
            [JavascriptInterface]
            [Export("invokeAction")]
            public void InvokeAction(string data)
            {
                HybridWebViewRenderer hybridRenderer;
                if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
                {
                    ((HybridWebView)hybridRenderer.Element).InvokeAction(data);
                }
            }
        }
    
        //this methods html file content from assets folder
        public string LoadData(string inFile)
        {
            Stream stream = Android.App.Application.Context.Assets.Open(inFile);
            StreamReader sr = new StreamReader(stream);
            string text = sr.ReadToEnd();
            sr.Close();
            return text;
        }
    }

This is iOS renderer

[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace SfChatbot.iOS
{
    public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
    {
        const string JavascriptFunction = "function initESW(data){jsBridge.invokeAction(data);}";
        //const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
        WKUserContentController userController;

        public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
        {
        }

        public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
        {
            userController = config.UserContentController;
            var script = new WKUserScript(new NSString(JavascriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
            userController.AddUserScript(script);
            userController.AddScriptMessageHandler(this, "invokeAction");
        }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                userController.RemoveAllUserScripts();
                userController.RemoveScriptMessageHandler("invokeAction");
                HybridWebView hybridWebView = e.OldElement as HybridWebView;
                hybridWebView.Cleanup();
            }

            if (e.NewElement != null)
            {
                base.OnElementChanged(e);
                var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SfChatbot.iOS.HybridWebViewRenderer)).Assembly;
                Stream stream = assembly.GetManifestResourceStream("SfChatbot.iOS.Resources.ChatUAT.html");

                string content1 = "";
                using (var reader = new System.IO.StreamReader(stream))
                {
                    content1  = reader.ReadToEnd();
                }

                LoadSimulatedRequest(new NSUrlRequest( new NSUrl("https://service.force.com/embeddedservice/5.0/esw.min.js")), content1);
                
            }
        }

        public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
        {
            ((HybridWebView)Element).InvokeAction(message.Body.ToString());
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ((HybridWebView)Element).Cleanup();
            }
            base.Dispose(disposing);
        }

        //not being used
        public string LoadUATData()
        {
            var uri = new UriBuilder("https://run.mocky.io/v3/37c8-1f4501adeeff").Uri;
            ServicePointManager.ServerCertificateValidationCallback = new
                RemoteCertificateValidationCallback
                (
                   delegate { return true; }
                );
            var client = new WebClient();
            var content = client.DownloadString(uri);

            //SMS UAT
            var content1 = content.Replace("t1", "https.my.salesforce.com").
               Replace("t2", "https://.cs81.force.com").
               Replace("t3", "00D260009").
               Replace("t4", "5260000004C").
               Replace("t5", "573200004").
               Replace("t6", "EmbeddedServiceLiveAgent_Parent04I260000000AIbca0f71c").
               Replace("t7", "https://salesforce.com/embeddedservice/5.0/esw.min.js").
               Replace("path", "src");

            return content1;
        }
    }

Salesforce providing javacript file, we need to convert that into html format a nd keep in Assets and Resource folder respectivly for android and iOS. If any page is not having CSS applied(after executing, in output), you need to add Lightings CSS styles in head tag of html file.

If there is any issue with keyboard is is hiding screen while typing, take help from this. Get the format for Salesforce chat file, from this question.

R15
  • 13,982
  • 14
  • 97
  • 173
  • are you able to make the SDK work by converting from jar to C#? or did you just went with the webview approach? – Nalluri Feb 22 '23 at 17:57
  • 1
    Jar file or nuget doesn't work for me. I just used webview with c# code. – R15 Feb 23 '23 at 04:27