JavaScript Interface not working in my Android App

2019-06-07 05:46发布

问题:

Following is my MainActivity class code

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // setContentView(R.layout.activity_main);
    WebView webView = new WebView(this);

    //add the JavaScriptInterface so that JavaScript is able to use LocalStorageJavaScriptInterface's methods when calling "LocalStorage"
    webView.addJavascriptInterface(new LocalStorageJavaScriptInterface(this), "LocalStorage");

    WebSettings settings = webView.getSettings();
    // TO enable JS
    settings.setJavaScriptEnabled(true);
    // To enable Localstorage
    settings.setDomStorageEnabled(true);

    //those two lines seem necessary to keep data that were stored even if the app was killed.
    settings.setDatabaseEnabled(true);
 /*   
    webView.setWebChromeClient(new WebChromeClient() { 
        public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) { 
                quotaUpdater.updateQuota(5 * 1024 * 1024); 
            } 
        });*/

    //load HTML File in webview
    webView.loadUrl("file:///android_asset/main.html");

    setContentView(webView);
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
  //  getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


/**
 * This class is used as a substitution of the local storage in Android webviews
 * 
 * @author Diane
 */
public class LocalStorageJavaScriptInterface {
        private Context mContext;
        private LocalStorage localStorageDBHelper;
        private SQLiteDatabase database;

        LocalStorageJavaScriptInterface(Context c) {
                mContext = c;
                localStorageDBHelper = LocalStorage.getInstance(mContext);
        }

        /**
         * This method allows to get an item for the given key
         * @param key : the key to look for in the local storage
         * @return the item having the given key
         */
        @JavascriptInterface
        public String getItem(String key)
        {
                String value = null;
                if(key != null)
                {
                        database = localStorageDBHelper.getReadableDatabase();
                        Cursor cursor = database.query(LocalStorage.LOCALSTORAGE_TABLE_NAME,
                                        null, 
                                        LocalStorage.LOCALSTORAGE_ID + " = ?", 
                                        new String [] {key},null, null, null);
                        if(cursor.moveToFirst())
                        {
                                value = cursor.getString(1);
                        }
                        cursor.close();
                        database.close();
                }
                return value;
        }

        /**
         * set the value for the given key, or create the set of datas if the key does not exist already.
         * @param key
         * @param value
         */
        @JavascriptInterface
        public void setItem(String key,String value)
        {
                if(key != null && value != null)
                {
                        String oldValue = getItem(key);
                        database = localStorageDBHelper.getWritableDatabase();
                        ContentValues values = new ContentValues();
                        values.put(LocalStorage.LOCALSTORAGE_ID, key);
                        values.put(LocalStorage.LOCALSTORAGE_VALUE, value);
                        if(oldValue != null)
                        {
                                database.update(LocalStorage.LOCALSTORAGE_TABLE_NAME, values, LocalStorage.LOCALSTORAGE_ID + " = " + key, null);
                        }
                        else
                        {
                                database.insert(LocalStorage.LOCALSTORAGE_TABLE_NAME, null, values);
                        }
                        database.close();
                }
        }

        /**
         * removes the item corresponding to the given key
         * @param key
         */
        @JavascriptInterface
        public void removeItem(String key)
        {
                if(key != null)
                {
                        database = localStorageDBHelper.getWritableDatabase();
                        database.delete(LocalStorage.LOCALSTORAGE_TABLE_NAME,   LocalStorage.LOCALSTORAGE_ID + " = " + key, null);
                        database.close();
                }
        }

        /**
         * clears all the local storage.
         */
        @JavascriptInterface
        public void clear()
        {
                database = localStorageDBHelper.getWritableDatabase();
                database.delete(LocalStorage.LOCALSTORAGE_TABLE_NAME, null, null);
                database.close();
        }
}

}

Basically I am using AndroidLocalstorage plugin https://github.com/didimoo/AndroidLocalStorage which is basically used as a fallback option to localStorage.

Following is my AndroidMainifest.xml

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android_playlist"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name="android.permission.INTERNET"></uses-permission>



    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.android_playlist.MainActivity"
            android:label="@string/app_name" 
            android:screenOrientation="portrait"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

    </manifest>

Basically the issue is that the javascriptInterface is NOT working for me.

I have added following lines of code in my js file which loads

try{
    //we replace default localStorage with our Android Database one
    window.localStorage=LocalStorage;    
}catch(e){
    //LocalStorage class was not found. be sure to add it to the webview
        console.log("error", e);
        console.log("LocalStorage ERROR : can't find android class LocalStorage. switching to raw localStorage")              
   }

But when I checked the browser console I always get the console.log which is in catch.

Can some one please throw some light on what is wrong with my code and why the Javascript interface is NOT working for me.

Following is the error I am getting in the console

{stack: (...), message: "LocalStorage is not defined"} 

One IMP thing I forgot to mention is that I am testing this on my laptop browser by simply loading the HTML file using file: protocol. Does this matter?

回答1:

window.localStorage=LocalStorage; 

above code gives meaning that window object has the property named localStorage and your trying set its value as LocalStorage. LocalStorage object created for you by android that can be guarantied but ultimately localStorage property for window object no guaranty.so the exception is thrown. Hope this ans will help you.



回答2:

I finally found out the issue in my code, In AndroidMainifest XML my targetSDK version was 18. it should have been 19 as I am not setting up database path as well as database size in my MainActivity.

Original Code

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="18" />

Changed Code

<uses-sdk 
    android:minSdkVersion="14" 
    android:targetSdkVersion="19" />