Android Webview - detect jquery document ready - javascript

I use an Android Webview to convert a website to an android app. The website uses many JavaScript files and many of them start at $(document).ready(). The website works great, but the app recognizes only the $(document).ready() from the first file. "console.log("anything");" placed on second file run only if it is outside of $(document).ready().

// Java
private void javaRun(String script)
{
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
myWebView.evaluateJavascript(script, null);
} else {
myWebView.loadUrl(script);
}
}
#Override
public void onPageFinished(final WebView view, String url) {
super.onPageFinished(view, url);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
javaRun("javascript:ready();");
}
}, 200);
}
// Javascript
function ready()
{
$('li').click(function(){
$(this).toggleClass('read');
});
}

Related

Refresh WebView contents from a JS bridge in JavaFX

I am creating an AppDrawer (all in one place to launch shortcuts).
My JSCallBack bridge class has a method that should delete a shortcut, then refresh the page. But, it is unable to successfully refresh the page.
AppDrawerMain.java
public class AppDrawerMain extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(AppDrawerMain.class.getResource("main.fxml"));
Parent root = (Parent) fxmlLoader.load();
Scene scene = new Scene(root, 1280, 720);
String css = this.getClass().getResource("application.css").toExternalForm();
scene.getStylesheets().add(css);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
AppDrawerController.java
public class AppDrawerController implements Initializable {
#FXML
private Button refreshButton;
#FXML
private WebView webView;
WebEngine webEngine;
JSCallBack jsCallBack;
//this function essentially generates the html code for the webview
public String loadApps(){
return "<div class=\"container\"><img src=\"file:/"+imagePath+"\"/><p class=\"title\">"+displayName+"</p><div class=\"overlay\"></div><div class=\"button-open\" onclick=\"app.processOnClickOpen(\'"+id+"\')\"> Open </div><div class=\"button-option\" onclick=\"app.processOnClickOption(\'"+id+"\')\"> Edit </div></div>"
}
//refresh the page
private void refreshPage(String html){
webEngine.loadContent(html);
webEngine.reload();
}
#SneakyThrows
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
refreshButton.setOnAction(event -> {
refreshPage(loadApps());
});
webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((obs, oldValue, newValue)-> {
if (newValue == Worker.State.SUCCEEDED) {
JSObject jsObject = (JSObject) webEngine.executeScript("window");
jsCallBack = new JSCallBack(webEngine); //declared this way to avoid GC
jsObject.setMember("app", jsCallBack);
}
});
webEngine.setJavaScriptEnabled(true);
var html = loadApps();
webEngine.loadContent(html);
}
//The bridge class
public class JSCallBack {
protected JSCallBack() {}
//no refresh needed here
public void processOnClickOpen(String id) {
log("Before open");
onAppOpen(id);
log("After open");
}
//The part that isnt working
public void processOnClickOption(String id) {
//deleting the apps works fine
webEngine.loadContent(loadApps()+loadApps()); //trying to refresh the page isnt fine
webEngine.reload();
}
}
}
The problem I am having is here:
public void processOnClickOption(String id) {
//refreshPage(loadApps()+loadApps()) (not working either)
//refreshButton.fire() (not working either)
webEngine.loadContent(loadApps()+loadApps()); //trying to refresh the page isnt fine
webEngine.reload(); //not working
}
I tried adding location.reload() to the JavaScript function in the script itself, but it did not work.
I tried adding the refreshButton.fire() to the processOnClickOption(), which should reload the page if clicked on manually, but it did work either.
I tried to set a new WebEngine in the bridge class itself. Also, it did not work.
I added a log to see if there was an issue with threading, but WebEngine mentions that it was on the JavaFX Application thread, so that is not the problem either.
This is the main WebView:
If I click on the edit button, it should remove it from the WebView and refresh the page like this expected outcome:
Unfortunately, after clicking the edit button it will delete the files on the backend side, but the WebView is not refreshed, so the app stays there. I would like to get help on this.

android studio webview get data and onfinish

I have an android activity that holds the webview and I have a page that contains a local variable marks. The local variable will be increased when user got the correct answer. In the webpage, there is a button called exit which is supposed to close the webpage and go back to the activity in android, and it should carry the local variable marks back to the activity too. I want to ask how the exit button can be done in the webpage to close the page and return local variable by using Javascript and how can the activity in android receive the local variable from the webpage.
My activity in android:
private WebView webview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
webview = new WebView(this);
webview.getSettings().setJavaScriptEnabled(true);
try {
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("file:///android_asset/index.html");
}
catch(Exception ex)
{
ex.printStackTrace();
}
setContentView(webview);
}
My exit button is a div:
<div class="exit" onclick="finish()">Exit</div>
I am going to use the finish() function to return the variable and close the webpage back to the activity in android.
function finish() {}
To notify the host application that a page has finished loading. Then Call onPageFinished()
webview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
}
});
SOURCE
you can do one thing..On click on the exit call any url like http://../getmark?marks=2 and once url load in the webview finish/ exit from webview. In the activity
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// parse the url here to get marks
}
});
Register a javascriptinterface to your webview in onCreate:
this.webview.addJavascriptInterface(new MyJSInterface(this), "Android");
Implement setCount method in your Activity:
public void setCount (int count) {
//do what ever you want with count
}
Make a new JavascriptInterface-Class:
public class MyJSInterface {
private YourActivity yourActivity = null;
public MyJSInterface (YourActivity yourActivity) {
this.yourActivity = yourActivity;
}
#JavascriptInterface
public void invoke (int count) {
this.yourActivity.setCount(count);
}
}
And in javascript:
function finish(marks) {
if (Android !== undefined) {
if (Android.invoke !== undefined) {
Android.invoke(marks);
}
}
}

Javascript not always working in WebView

I want to open a webpage in a WebView and click automatically on a button after the page has loaded. This is my current WebView class:
public class WebViewFragment extends Fragment {
...
#Override
public void onResume() {
super.onResume();
openUrl();
}
private void openUrl() {
setCookies();
if (urlToOpen != null) {
//tell webview to handle redirects (by default browser launches on redirects)
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (getActivity() != null)
((MainActivity) getActivity()).onShowLoading();
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (getActivity() != null) {
executeJS();
((MainActivity) getActivity()).onHideLoading();
}
}
});
if (javascriptToExecute != null) {
webview.getSettings().setJavaScriptEnabled(true);
}
webview.loadUrl(urlToOpen);
}
}
private void executeJS() {
System.out.println("executeJS(): " + javascriptToExecute);
webview.loadUrl(javascriptToExecute);
}
}
I can use "javascript:$('#customer-info-edit').click();" or "javascript:document.getElementById('customer-info-edit').click();" both work fine.
But the problem is they work only one time. If I open the WebView for the first time, the button is clicked. However if I press physical back button and open the WebView again then the button is not clicked. Why isn't Javascript working every time?
I don't know what the problem exactly was, but I found a working solution: add 500ms delay before executing javascript.

JavaScript function in WebView and ViewPager

I have a problem with Javascript in WebView. Currently I have a ViewPager, which adds View dynamically when needed. Before add a view to viewpager, I inflate it and load an embedded webview inside:
LayoutInflater inflater = this.getLayoutInflater();
FrameLayout v = (FrameLayout) inflater.inflate(R.layout.notebook_page, null);
setupWebView(v);
pagerAdapter.addView(v);
pagerAdapter.notifyDataSetChanged();
In the webview, first I load a local html, and then inject a JS fuction to set several input on HTML.
private void setupWebView(View v) {
myWebView = (WebView) v.findViewById(R.id.webview);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.loadUrl("file:///android_asset/web_resources/index.html");
myWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
super.onPageFinished(myWebView, url);
Log.d("WebView Content", "Injecting JS");
myWebView.loadUrl("javascript:function('" + input_var + "')");
}
});
}
Funtion setupWebView is called correctly for every view inflated, however, the JS function does not work properly
The same piece of code works perfectly in an Activity, if there is only 1 page. Just in ViewPager, where there are more than 1 pages to display the webviews, JS only loads in the last page.
Do you have any suggestion?
Firstly, on 5.0 Android you should use different method to use javascript. I use this snippet of code.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("javascript:window.HTMLOUT.processHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
Log.e("LoginActivity onReceiveValue", s);
}
});
} else
webView.postUrl("javascript:window.HTMLOUT.processHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');", null);
Also, you should include #JavascriptInterface tag on your javascript method.
#SuppressWarnings("unused")
#JavascriptInterface
public void processHTML(final String html) {
//method called from javascript
}

Dynamically injecting swfupload.js into a GWT project. JS code is unintentionally called before <span> exists in DOM

I'm attempting to inject a swfupload.js into a GWT project to support multifile upload. I have a version of the swfupload.js running locally on a non-GWT project but I'm having difficulty integrating it into the GWT project.
I suspect that the JS is being called before the <span> element exists in the DOM. The JS script is injected when an upload modal dialog appears, after adding a breakpoint at swfupload.js > loadFlash() and inspecting the targetElement it comes back as undefined when it should be the #btnFileUpload span. Additionally, I could see the <span> on screen when the script stops on the breakpoint.
With the breakpoint, querying for $('#btnFileUpload') in console I
get [].
Without the breakpoint, querying for $('#btnFileUpload')
in console I get <span id="btnFileUpload">...</span>.
Script Injector code in GWT/Java (works to the best of my knowledge)
#UiFactory
FormPanel createForm() {
[...]
String baseURL = GWT.getHostPageBaseURL();
ScriptInjector.fromUrl(baseURL + "js/jquery.min.js").inject();
String[] files = {
"swfupload.js",
"handlers.js",
"swfupload.queue.js",
"fileprogress.js",
"swfupload.impl.js"
};
for (String file : files) {
ScriptInjector.fromUrl(baseURL + "js/swfupload/" + file).inject();
}
[...]
}
JavaScript: swfupload.impl.js
var swfu;
$('#btnFileUpload').ready(function() {
var settings = {
button_placeholder_id: "btnFileUpload"
[...]
};
swfu = new SWFUpload(settings);
}
JavaScript: swfupload.js
// Gets called from SWFUpload 'constructor'
SWFUpload.prototype.loadFlash = function () {
var targetElement, tempParent;
[...]
// Get the element where we will be placing the flash movie
targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
if (targetElement == undefined) {
throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
}
[...]
};
Note: I know there is an implentation of SWFUpload for GWT but I'd rather not go that route.
When you use ScriptInjector the scripts get added to the page using an IFrame so your scripts are running within their own browsing context. The document.getElementById in swfupload.js is accessing it's "own DOM" rather than the top-level one. You can try accessing the parent context, that probably has the span you're looking for, by using window.parent.
Here is an example for loading multiple js into GWT
ScriptInjector.fromUrl(GWT.getModuleBaseURL() + "lodash.js").setWindow(ScriptInjector.TOP_WINDOW)
.setCallback(new Callback<Void, Exception>() {
#Override
public void onFailure(Exception reason) {
System.out.println("lodash loading failed");
}
#Override
public void onSuccess(Void result) {
System.out.println("lodash loaded");
}
}).inject();
ScriptInjector.fromUrl(GWT.getModuleBaseURL() + "jquery.js").setWindow(ScriptInjector.TOP_WINDOW)
.setCallback(new Callback<Void, Exception>() {
#Override
public void onFailure(Exception reason) {
System.out.println("jquery loading failed");
}
#Override
public void onSuccess(Void result) {
System.out.println("jquery loaded");
}
}).inject();
ScriptInjector.fromUrl(GWT.getModuleBaseURL() + "backbone.js").setWindow(ScriptInjector.TOP_WINDOW)
.setCallback(new Callback<Void, Exception>() {
#Override
public void onFailure(Exception reason) {
System.out.println("backbone loading failed");
}
#Override
public void onSuccess(Void result) {
System.out.println("backbone loaded");
}
}).inject();
ScriptInjector.fromUrl(GWT.getModuleBaseURL() + "joint.min.js").setWindow(ScriptInjector.TOP_WINDOW)
.setCallback(new Callback<Void, Exception>() {
#Override
public void onFailure(Exception reason) {
System.out.println("joint.min loading failed");
}
#Override
public void onSuccess(Void result) {
System.out.println("joint.min loaded");
}
}).inject();

Categories

Resources