stringByEvaluatingJavascriptFromString (iOS method, what is Android equivalent?) - java

In an iOS app, I used
stringFromJavaScript = [webView stringByEvaluatingJavascriptFromString:#"document.getElementById(\"image\").getAttribute(\"src")"];
To get the src directory of the image that was being displayed on the webView. I want to do the same for Android. What are my options?
Basically the intent is to capture the path so that I can email this same picture...
ie.
"picture.php?image=%#",stringFromJavascript
This way, that same image would be loaded when the user clicks the link, or posts it to facebook etc.

Yeah, I miss this method greatly in Android ;)
To execute JavaScript and get response you can do as follows:
Define JavaScript callback interface in your code:
class MyJavaScriptInterface {
#JavascriptInterface
public void someCallback(String jsResult) {
// your code...
}
}
Attach this callback to your WebView
MyJavaScriptInterface javaInterface = new MyJavaScriptInterface();
yourWebView.addJavascriptInterface(javaInterface, "HTMLOUT");
Run your JavaScript calling window.HTMLOUT.someCallback from the script:
yourWebView.loadUrl("javascript:( function () { var resultSrc = document.getElementById(\"image\").getAttribute(\"src\"); window.HTMLOUT.someCallback(resultSrc); } ) ()");
Hope this helps!

Related

Google ad click is not opening the external web browser

I am trying to implement the ad in my app with Custom Native Ad Format - https://developers.google.com/ad-manager/mobile-ads-sdk/android/native/custom-formats#java_1
So, according to the documentation I am going with the approach described there and creating the ad
...
private void setListeners() {
...
imageView.setOnClickListener(v -> {
nativeCustomFormatAd.performClick("IMAGE");
});
...
}
private NativeCustomFormatAd nativeCustomFormatAd;
AdLoader adLoader = new AdLoader.Builder(context, "/6499/example/native")
.forCustomFormatAd("10063170",
new NativeCustomFormatAd.OnCustomFormatAdLoadedListener() {
#Override
public void onCustomFormatAdLoaded(NativeCustomFormatAd ad) {
// Show the custom format and record an impression.
nativeCustomFormatAd = ad;
Drawable drawable = vm.nativeCustomFormatAd.getImage("IMAGE").getDrawable();
imageView.setDrawable(drawable);
}
},
new NativeCustomFormatAd.OnCustomClickListener() {
#Override
public void onCustomClick(NativeCustomFormatAd ad, String s) {
// Handle the click action
}
})
.withAdListener( ... )
.withNativeAdOptions( ... )
.build();
#SuppressLint("VisibleForTests")
AdManagerAdRequest adManagerAdRequest = new AdManagerAdRequest.Builder().build();
adLoader.loadAd(adManagerAdRequest);
...
So, it looks pretty simple I try to make a request for the ad then I got (in a callback) NativeCustomFormatAd, save it as a class member, and along with it get drawable and set it to the imageView (to present it in the UI). Once a user clicks on the imageView I get an event in the click listener and invoke nativeCustomFormatAd.performClick("IMAGE");.
The problem is that I expect that once I transfer the ad click to the SDK (by nativeCustomFormatAd.performClick("IMAGE");) SDK is supposed to open the external browser, but instead nothing happens.
P.S. I am sure that nativeCustomFormatAd.performClick("IMAGE"); getting invoked and also I see that SDK gets the click as I got a callback event here:
...
new NativeCustomFormatAd.OnCustomClickListener() {
#Override
public void onCustomClick(NativeCustomFormatAd ad, String s) {
// Handle the click action
}
})
...
What am I missing here?
According to the docs you linked:
When a click is performed on a custom format ad, there are three possible responses from the SDK, attempted in this order:
Invoke the OnCustomClickListener from AdLoader, if one was provided.
For each of the ad's deep link URLs, attempt to locate a content resolver and start the first one that resolves.
Open a browser and navigate to the ad's traditional Destination URL.
Also:
If you pass a listener object in, the SDK instead invokes its onCustomClick method and takes no further action.
Therefore, it seems you have to pass a null OnCustomClickListener.

Change URL while loading it in browser - Android Studio

I have created an app that will load links from my server into the webview. However, I have also written an intent to open the link in the user's browser so they can download the file. I want the link to change a bit while it loads in the browser.
I.e:
This is the link : https://www.example/v/file
My app should change "v" to "f" and load in the user's browser.
Like this: https://www.example/f/file
My code:
private void initWebDowload(String s){
webView.loadUrl(s);
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(s));
startActivity(i);
}
Kinda complicated but you need to attach a custom WebViewClient to your WebView so you can change the URL loading behaviour.
Just to give an example:
webView.setWebViewClient(new CustomWebViewClient());
private class CustomWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// right here you are given the chance to change the [url] ^
view.loadUrl(url.replace("/v/file", "/f/file")); // replace v with f
return true;
}
}
}

Cordova Jquery Mobile Local Notification onclick change page

I'm sorry for the long post, but I think this is the only way to explain whats happening... I'm looking for help after a lot of research with no answers... A big problem I think...
So this web app schedule a local notification based on a time picker that the users interact with..
I'm using cordova and jquery mobile multi-page system... It changes from page to page by div IDs, the navigation looks like this: index.html, index.html#page2, index.html#page3..
The local notification is a java plugin for cordova Katzer Local Plugin.
The plugin only works inside the onDeviceReady function and the jquery mobile does not, like this...
document.addEventListener('deviceready', onDeviceReady, false);
/* JQUERY MOBILE HERE */
$(document).on("pagecreate", "#home", function(event) {
$("a#btnpage2").click(function (e) {
e.stopImmediatePropagation();
e.preventDefault();
$( "#page2" ).pagecontainer( "change"); // change to #page2
});
});
$(document).on("pagecreate", "#page2", function(event) {
console.log("#page2 created");
});
function onDeviceReady(){
/* NOTIFICATION PLUGIN HERE */
//create notification
var msg = "notification message";
window.plugin.notification.local.add({
id: 'notif',
date: dateobject,
message: msg,
json: JSON.stringify({ test: msg }),
title: 'Title',
autoCancel: true,
ongoing: false
});
//onclick event notification
window.plugin.notification.local.onclick = function (notif, state, json) {
var msg = JSON.parse(json).test;
$( "#notificationPage" ).pagecontainer( "change", { text: msg} ); //pass data and change to #page2
}
//ontrigger notification
window.plugin.notification.local.ontrigger = function (notif, state, json) {
var msg = JSON.parse(json).test;
}
}
When the notification is fired, and when I click it, it should change the page to #notificationPage.
The problem is that the command inside onclick, does not work even when I click the notification with the app running, it throws this error:
Uncaugh Error: cannot call methods on pagecontainer prior to initialization; attempted to call method 'change'.
However the following command DOES change the page, found it on google: $.mobile.changePage( "#notificationPage" ). But only if the app is running and not interrupted. I think that if its in background or closed even if its not interrupted, it doesn't change the page... it opens the activity defined by the plugin. When I say in background or closed and not interrupted i mean that app was closed by the main button and not the back button that completely closes the app..
I guess this is the classes that handle the notification:
/* Receiver.class notification plugin */
Intent intent = new Intent(context, ReceiverActivity.class)
.putExtra(OPTIONS, options.getJSONObject().toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
int requestCode = new Random().nextInt();
PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
return notification.setContentIntent(contentIntent);
/* ReceiverActivity.class notification plugin */
Context context = getApplicationContext();
String packageName = context.getPackageName();
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
launchIntent.putExtra("MSG", msgJson); // here I pass the json message to the new intent, thats gonna open when clicking the notification
context.startActivity(launchIntent);
So basically, I want to click the notification, and open a specific page, so I can get the json value on click and pass to that page and then display it to a div element... It seems I can't use the notification plugin commands outside the onDeviceReady, and neither jquery mobile commands inside the onDeviceReady.... Beside that I have to deal with the problem that is to do the same thing if the app is closed and interrupted...
At the java side, I could create another activity along with the main cordova app activity, and create a layout in xml, and add a textview... On the .java file of this new activity I think I could set the setContentView to this xml layout, and set the text of the textView to the json object value I want... this json value is the same as the message of the notification... I pretty sure, like 95% convinced this would work, not tested yet, but the thing is, its hard to maintenance.
What I tried is create this new activity, exactly like the main activity of cordova, but the loadUrl, I set to the page I want to go, not to LaunchUrl, which loads the address from config.xml of cordova, and passed the json value that I added as extra on the intent creation as a url param so on the jquery mobile side I could take the document.URL and the parameter... like this, first I edited the ReceiverActivity.class from notification plugin:
/* ReceiverActivity.class notification plugin */
Context context = getApplicationContext();
//String packageName = context.getPackageName();
Intent launchIntent = new Intent(context, NotificationActivity.class);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
launchIntent.putExtra("MSG", msgJson);
context.startActivity(launchIntent);
/* NotificationActivity.class cordova app second activity */
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String msg;
Intent intent = getIntent();
Bundle extras = intent.getExtras();
msg = extras.getString("MSG");
String utf_encoded = null;
try {
utf_encoded = URLEncoder.encode(msg,"UTF-8");
} catch (UnsupportedEncodingException e) {}
String url = "file:///android_asset/www/index.html#notificationPage?parameter="+utf_encoded;
super.loadUrl(url);
}
And on the javascript side, I could retrive that parameter in the url:
document.addEventListener('deviceready', onDeviceReady, false);
$( document ).on( "pagebeforechange" , function ( event, data ) {
if ( data.toPage[0].id == "notificationPage" ) {
var url = document.URL;
var urlParams = decodeURIComponent(url);
var onlyParams = urlParams.split('=')[1];
var newchar = " ";
var paramValue = onlyParams.split('+').join(newchar);
$('#notificationPage #showMessage').empty();
$('#notificationPage #showMessage').append("<p>Message: " + paramValue + "</p>");
}
});
function onDeviceReady(){
/* ondeviceready */
}
This actually worked, but it has some bugs... Sometimes the page loads, sometimes the page doesn't load, the page sometimes turned to a black screen... It works specially if the app is closed and interrupted, but if its open, most of the times it goes to a black screen... and if I click the back button on the device, it "navigates back", but it actually goes to the page that should be activated and showing the message... its like the page is behind this black screen sometimes and it won't come out to front unless I use back button..
I'm out of options... tried almost everything with no concrete and stable solution.. Flags, javascript, java, redirect url at javascript, at java, nothing seems to work...
Well I'm not a developer. I'm a designer, putting all my efforts to finish this... but god, its hard.... Theoretically a easy solution would be leaving everything at defaults, and when the plugin "launch" the app or the intent, or whatever by clicking the notification, just run a javascript with the command from jquery mobile that change pages... That would be amazing! hahah
I really need help..
Thanks to everyone that is reading this... To everyone that will try to help me...
Thank you all
Use this method:
cordova.plugins.notification.local.on("click", function (notification) {
alert(notification.text);
}, scope);
Here is the updated doc.
Cordova Jquery Mobile Local Notification onclick change page

How to call javascript function from java when webview page is different

I am working on an android project using HTML and webview to display.
I have
display.loadUrl("file:///android_asset/index.html");
display.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url)
{
display.loadUrl("javascript:openDialog()");
}
});
and this works perfectly. But the javascript function i want to call is in another page (chat.html). How do i call the javascript functions on this pages from java?
If you are the owner of the webpage (chat.html), you can integrate a JS-function which invokes a native method. And in this native method you can call your target-JS:
chat.html:
function callItNow() {
if (typeof Android != "undefined"){
if (Android.caller!= "undefined") {
Android.caller();
}
}
}
in native Code, define a class:
class MyJavascriptBridge {
public void caller() {
//now you know you are on the right place (chat.html)
webView.loadUrl("javascript:openDialog()");
}
}
and of course you have to declare the bridge to your webview:
webView.addJavascriptInterface(new MyJavascriptBridge(), "Android");
suppose you'r function in javascript is hello.
webview.loadUrl("javascript:hello();");
I think that'll do it.

Android WebView getFavicon() returning null

I'm trying to get the favicon of the loaded page after using
WebView webView = new WebView(getActivity());
webView.loadUrl("http://" + url);
I'm attaching the asynchronous WebViewClient to the WebView to get the favicon after it loads
webView.setWebViewClient(new WebViewClient()
{
#Override
public void onPageFinished(WebView view, String url)
{
String linkTitle = view.getTitle();
Bitmap favicon = view.getFavicon();
onLinkUrlFinished(url, linkTitle);
}
});
The favicon getting back is always null, even for websites such as google/facebook that has favicons for sure.
Another thread says to use WebIconDatabase but it's deprecated:
Display the Android WebView's favicon
The API on android site refers to WebViewClient.onReceivedIcon which doesnt even exist.http://developer.android.com/reference/android/webkit/WebView.html#getFavicon%28%29
What's going on here?
In order to use onReceiveIcon(), you should use setWebChromeClient.
This is what I do and it's working for me.
webView.setWebChromeClient(new WebChromeClient() {
#Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
progressBar.setProgress(newProgress);
}
#Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
webImage.setImageBitmap(icon);
}
});
WebIconDatabase is deprecated as of API 19. According to the comments in the code:
#deprecated This class is only required when running on devices up to
{#link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}
So unless you don't want to support API 18 and below, you should still be using WebIconDatabase:
WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath());
And then, regardless what API you want to support, you need to specify in a custom WebChromeClient:
public class MyCustomWebChromeClient extends WebChromeClient {
#Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
// do whatever with the arguments passed in
}
}
Remember to register your custom WebChromeClient with your WebView:
mWebView.setWebChromeClient(new MyCustomWebChromeClient());
The key is to open the WebIconDatabase so WebView has somewhere to put the icons, and override WebChromeClient.onReceivedIcon. For additional information, see this StackOverflow article.
I know its an old thread but, for those facing problems getting favicon using webview client.
Kotlin:
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
tabTitle.text = view?.title // read website title
loadImg(view) // method to load the favicon
}
private fun loadImg (view: WebView?){
// u can directly use tabImage.setBitmap instead of assigning tabImg as val
val tabImg: ImageView = findViewById(R.id.tabImage)
// creating handler object to delay the associated thread a little bit after onPageFinished is called.
val handler = Handler()
val runnable = Runnable {
if(view?.favicon != null) {
tabImg.setImageResource(0) //remove the default image
tabImg.setImageBitmap(view?.favicon) // set the favicon
}
}
handler.postDelayed(runnable, 200) // delay time 200 ms
}
It worked for me, hope it helps new readers, plz up vote if it helps u, so that u can help others!
Best regards
So in the end I didn't end up using the deprecated API, instead I found out that if you put /favicon.ico after the domain, it'll give you the ico file, which I used in the end to fetch the image. The Uri API will have a getHost() method that will give you the host without having to manually parse it
String faviconUrl = Uri.parse(url).getHost() + "/favicon.ico";
For google for example the icon url will be www.google.com/favicon.ico

Categories

Resources