Skip to content

Commit

Permalink
CB-11292 fix broken MessageChannel after plugins are recreated
Browse files Browse the repository at this point in the history
This closes apache#307
  • Loading branch information
tony-- authored and infil00p committed May 25, 2016
1 parent 9738079 commit ecb99c9
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
1 change: 1 addition & 0 deletions framework/src/org/apache/cordova/CordovaWebViewImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public void loadUrlIntoView(final String url, boolean recreatePlugins) {
if (recreatePlugins) {
// Don't re-initialize on first load.
if (loadedUrl != null) {
appPlugin = null;
pluginManager.init();
}
loadedUrl = url;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.apache.cordova.test;
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/


import android.view.KeyEvent;
import android.view.inputmethod.BaseInputConnection;

import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaWebViewImpl;
import org.apache.cordova.PluginManager;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class MessageChannelMultiPageTest extends BaseCordovaIntegrationTest {
private static final String START_URL = "file:///android_asset/www/backbuttonmultipage/index.html";

@Override
public void setUp() throws Exception {
super.setUp();
setUpWithStartUrl(START_URL);
}

//test that after a page load the cached callback id and the live callback id match
//this is to prevent a regression
//the issue was that CordovaWebViewImpl's cached instance of CoreAndroid would become stale on page load
//this is because the cached instance was not being cleared when the pluginManager was reset on page load
//the plugin manager would get a new instance which would be updated with a new callback id
//the cached instance's message channel callback id would become stale
//effectively this caused message channel events to not be delivered
public void testThatCachedCallbackIdIsValid() throws Throwable {
Class cordovaWebViewImpl = CordovaWebViewImpl.class;
//send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of CoreAndroid)
Method method = cordovaWebViewImpl.getDeclaredMethod("sendJavascriptEvent", String.class);
method.setAccessible(true);
method.invoke(cordovaWebView, "testEvent");
sleep(1000);

//load a page - this resets the plugin manager and nulls cordovaWebViewImpl.appPlugin
//(previously this resets plugin manager but did not null cordovaWebViewImpl.appPlugin, leading to the issue)
runTestOnUiThread(new Runnable() {
public void run() {
cordovaWebView.loadUrl(START_URL);
}
});
assertEquals(START_URL, testActivity.onPageFinishedUrl.take());

//send a test event - this initializes cordovaWebViewImpl.appPlugin (the cached instance of CoreAndroid)
method.invoke(cordovaWebView, "testEvent");
sleep(1000);

//get reference to package protected class CoreAndroid
Class coreAndroid = Class.forName("org.apache.cordova.CoreAndroid");

//get cached CoreAndroid
Field appPluginField = cordovaWebViewImpl.getDeclaredField("appPlugin");
appPluginField.setAccessible(true);
Object cachedAppPlugin = appPluginField.get(cordovaWebView);
//get cached CallbackContext
Field messageChannelField = coreAndroid.getDeclaredField("messageChannel");
messageChannelField.setAccessible(true);
CallbackContext cachedCallbackContext = (CallbackContext) messageChannelField.get(cachedAppPlugin);

//get live CoreAndroid
PluginManager pluginManager = MessageChannelMultiPageTest.this.cordovaWebView.getPluginManager();
Field coreAndroidPluginNameField = coreAndroid.getField("PLUGIN_NAME");
String coreAndroidPluginName = (String) coreAndroidPluginNameField.get(null);
Object liveAppPlugin = pluginManager.getPlugin(coreAndroidPluginName);
//get live CallbackContext
CallbackContext liveCallbackContext = (CallbackContext) messageChannelField.get(liveAppPlugin);

//get callback id from live callbackcontext
String liveCallbackId = (liveCallbackContext != null) ? liveCallbackContext.getCallbackId() : null;
//get callback id from cached callbackcontext
String cachedCallbackId = (cachedCallbackContext != null) ? cachedCallbackContext.getCallbackId() : null;

//verify that the live message channel has been initialized
assertNotNull(liveCallbackId);
//verify that the cached message channel and the live message channel have the same id
assertEquals(liveCallbackId, cachedCallbackId);
}

private void sleep(int timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
fail("Unexpected Timeout");
}
}

}

0 comments on commit ecb99c9

Please sign in to comment.