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.