简体   繁体   中英

Call JavaScript from C# object in Xamarin

I have been able to call JavaScript from C# inside the MainActivity but I'm trying to do so from an object. The majority of my app runs inside a WebView, my JavaScript calls to my C# Interface invoking an asynchronous function and when it's complete I would like to call back to my JavaScript but am unable to do so. Here is my current setup: In my MainActivity I setup my WebView as such:

browser = FindViewById<WebView>(Resource.Id.mainView);
browser.SetInitialScale(1);
browser.SetWebChromeClient(new GeoWebChromeClient());
browser.Settings.UseWideViewPort = true;
browser.Settings.LoadWithOverviewMode = true;
if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
    WebView.SetWebContentsDebuggingEnabled(true);
}
browser.Settings.SetGeolocationEnabled(true);
browser.Settings.JavaScriptEnabled = true;
browser.AddJavascriptInterface(new JSCSMedium(this, ref browser), "Android");
browser.LoadUrl("file:///android_asset/web/index.html");

Then inside the JSCSMedium object I have an asynch function:

[Export]
[JavascriptInterface]
public void SyncApps()
{
    Task t = Task.Run(() => {

        IList<ApplicationInfo> tempApps = Application.Context.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchDirectBootAware);

        string packageName = "";
        string appName = "";

        for (int i = 0; i < tempApps.Count(); i++)
        {
            packageName = tempApps[i].PackageName;
            appName = tempApps[i].LoadLabel(manager);
            var root = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            var filePath = System.IO.Path.Combine(root, "system");
            filePath = System.IO.Path.Combine(filePath, packageName);

            if (!System.IO.Directory.Exists(filePath))
            {
                System.IO.Directory.CreateDirectory(filePath);
            }

            filePath = System.IO.Path.Combine(filePath, "icon.png");
            if (!System.IO.File.Exists(filePath))
            {
                Drawable icon = tempApps[i].LoadIcon(Application.Context.PackageManager);
                BitmapDrawable bd = (BitmapDrawable)icon;
                CreateAppIcon(bd.Bitmap, packageName);
            }

            Intent intent = Application.Context.PackageManager.GetLaunchIntentForPackage(packageName);
            if (intent != null)
            {
                apps.Add(tempApps[i]);
            }
        }
    });
}

If I don't do the C# as an async function it runs and returns data fine, but this process takes a bit of time and blocks the app temporarily. Inside my MainActivity I can call JavaScript just fine with:

browser.EvaluateJavascript("javascript: alert('fooBar');", null);

But browser is not accessible inside the JSCSMedium . I've tried passing the browser object as a reference and normally but it throws an exception stating that the EvaluateJavascript function must be called on the same thread as where it was instantiated. I've also tried sending a reference of my MainActivity to the JSCSMedium and call a function inside the MainActivity to run the EvaluateJavascript but it seems to do nothing. No error, not crash, just nothing.

The problem is Task.Run forces the code to run in the thread pool, and browser.EvaluateJavascript needs to run on the main thread.

You have at least two options here, depending on your needs:

1) Run the EvaluateJavascript call inside the Task.Run block with something like:

var h = new Handler(Looper.MainLooper);
h.Post(() => browser.EvaluateJavascript("javascript: alert('fooBar');", null));

2) Run the EvaluateJavascript call outside the Task.Run block:

[Export]
[JavascriptInterface]
public async void SyncApps()
{
    await Task.Run(() => {

    //...

    });

    browser.EvaluateJavascript("javascript: alert('fooBar');", null);
}

Not really sure if you can change the return type of SyncApps() . If JS doesn't complain, you better change that too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM