Search code examples
androidxamarin.androidandroid-webviewarabicmultilingual

WebView issue with ar_IL in Android 7+?


Fellow developers,

I'm creating an App and Android Vitals is showing an odd bug:

Issue: at (wrapper dynamic-method) System.Object.3(intptr,intptr,intptr)

android.runtime.JavaProxyThrowable: System.ArgumentOutOfRangeException: Not a valid calendar for the given culture.

This issue only happens in the following configuration ar_IL, I might be wrong, but I guess it means Arabic from Israel. I don't know how to test it or even how to choose it in the Emulator since I don't speak any language close to it. This is a preview of the bug:

error

Also, I uploaded the video of the bug (in fact the App is frozen and never opens):

https://youtu.be/aLXwEBHZnwA

It's quite strange since my App has been downloaded in different countries including some Arabic speaking ones like Saudi Arabia and I have never had any complain or notification that my App is not working or never opened for X or Y reason.

I'm going to add some parts of my code that I consider are connected to the WebView and it's opening and might be useful:

OnCreate function in C#:

public static bool RUN_ONCE { get; set; } = true;

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

    Rating();

    RequestWindowFeature(WindowFeatures.NoTitle);

    // Set our view from the "main" layout resource
    SetContentView(Resource.Layout.Main);

    WebView = FindViewById<WebView>(Resource.Id.webView);

    WebView.Settings.DomStorageEnabled = true;
    WebView.Settings.JavaScriptEnabled = true;
    WebView.Settings.AllowFileAccessFromFileURLs = true;

    WebView.AddJavascriptInterface(new CallJSInterface(this), "CSharp");

    WebView.SetWebViewClient(new JavaScriptWebViewClient($"javascript:firstExecTime({RUN_ONCE.ToString().ToLowerInvariant()});"));

    WebView.LoadUrl("file:///android_asset/index.html");

    if (Build.VERSION.SdkInt >= BuildVersionCodes.N)
    {
        StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
                            .PenaltyDeathOnFileUriExposure()
                            .Build();
        StrictMode.SetVmPolicy(policy);
    }

    RunOnce();
}

private void RunOnce()
{
    if (RUN_ONCE)
    {
        RUN_ONCE = false;
    }
}

firstExecTime function in JS:

function firstExecTime(firstTime) {
    isFirstTime = firstTime;
    if (firstTime)
        setFirstTimeValues();
}

And I have this process for setting different languages in JS (only supports English and Spanish at this point):

const androidLngLocation = "file:///android_asset/js/lang/";
var langs = ["en", "es"];
var langCode = "";
var currentTranslation;
var errorLng = false;

var translate = function (jsdata) {
    currentTranslation = jsdata;
    $("[tkey]").each(function () {
        $(this).html(jsdata[$(this).attr("tkey")]);
    });
    $("[tkey-title]").each(function () {
        $(this).prop("title", jsdata[$(this).attr("tkey-title")]);
    });
    $("[tkey-placeholder]").each(function () {
        $(this).prop("placeholder", jsdata[$(this).attr("tkey-placeholder")]);
    });
    $("[tkey-btn-ok]").each(function () {
        $(this).data("btn-ok-label", jsdata[$(this).attr("tkey-btn-ok")]);
    });
    $("[tkey-btn-cancel]").each(function () {
        $(this).data("btn-cancel-label", jsdata[$(this).attr("tkey-btn-cancel")]);
    });
    $("[tkey-data-title]").each(function () {
        $(this).data("title", jsdata[$(this).attr("tkey-data-title")]);
    });
};

langCode = navigator.language.substr(0, 2);

try {
    if (!langs.includes(langCode))
        langCode = "en";
    $.getJSON(`${androidLngLocation}${langCode}.json`, translate);
}
catch (e) {
    errorLng = true;
    setTimeout(function () {
        if (!isValueInArray(langs, langCode))
            langCode = "en";
        $.getJSON(`${androidLngLocation}${langCode}.json`, translate);
    }, 125);
}

function isValueInArray(arr, val) {
    inArray = false;
    for (i = 0; i < arr.length; i++)
        if (val === arr[i])
            inArray = true;
    return inArray;
}

Furthermore, here is a link of the logcat:

https://1drv.ms/t/s!AhpAtowYvNcyj-Fo1sIQUhu12Ce3Jw

I have some translations to English and Spanish from the Android resources for some small sections of the app like the NavigationDrawer, but I don't have any other translation and the default language is English in any other case.

Does anyone have ever experienced something similar? Do you know how to fix it? Or do you know how does it look the language in an emulator and I could test by myself? Thanks for your support.


Solution

  • I found a kind of workaround for my problem:

    if (new string[] { "ar_IL" }.Contains(Java.Util.Locale.Default.ToString()))
    {
        System.Globalization.CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
    }
    

    I consider it might help other people, what you need to do it's to define the incompatible languages that the Play Store provide you in the array and replace it by your default one or any compatible one that you have.

    I got this workaround from this discussion:

    https://bugzilla.xamarin.com/show_bug.cgi?id=59077

    It seems the bug is multiple languages like Thai, the workaround was provided by gcnew.