WebView callback from Javascript - webview

I tried to create a simple example of callback from Javascript to Java, based on the last example in WebEngine's javadoc (Calling back to Java from JavaScript). But when I click the link in the WebView, the Java method is not called and the page disappears.
public class TestOnClick extends Application {
#Override
public void start(Stage stage) throws Exception {
try {
final WebView webView = new WebView();
final WebEngine webEngine = webView.getEngine();
Scene scene = new Scene(webView);
stage.setScene(scene);
stage.setWidth(1200);
stage.setHeight(600);
stage.show();
String webPage = "<html>\n"
+ " <body>\n"
+ " Click here\n"
+ " </body>\n"
+ "</html>";
System.out.println(webPage);
webView.getEngine().loadContent(webPage);
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApp());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
public static class JavaApp {
public void onClick() {
System.out.println("Clicked");
}
}
}
Note: I don't see any exceptions being thrown in the WebView when monitoring the load worker with webView.getEngine().getLoadWorker().exceptionProperty().addListener(...).

You are trying to access webview DOM model before it was created.
Wrap your JavaApp related code to the page load listener to achieve your goal:
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
#Override
public void changed(ObservableValue<? extends State> ov, State t, State t1) {
if (t1 == Worker.State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApp());
}
}
});

Related

What happens if user clicks on deep link in the app itself

If I have created a deep link using the branch.io that opens a specific screen in my app. If this link is also available in my app and a user clicks on it, will it open my screen? or it will do nothing as the link I am trying to open from the app is pointing to the same app?
When you click on a Branch link within a webView in your App, you will have to handle the routing to the specific Activity, after reading the Branch link parameters.
Here is a sample Activity which contains a webView and and shows a couple of Branch links. When you click on a link in the webView it reopens the webview and displays the link parameters in a Toast message if a Branch link is clicked
public class MainActivity extends AppCompatActivity {
private WebView webView_;
private Button button_;
private String TAG = "WebViewController";
private Context context_;
private static final String URL_TO_LOAD = "https://evangelosg.github.io/index.html";
private static final String BRANCH_LINK_TO_LOAD = "https://ere6.app.link/b6sS0gsCfG";
#Override
protected void onNewIntent(Intent intent) {
Log.d("WebView", "onNewIntent");
setIntent(intent);
}
#Override
protected void onResume() {
super.onResume();
Branch branch = Branch.getInstance();
branch.initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
Log.d(TAG, referringParams.toString());
Toast.makeText(context_, referringParams.toString(), Toast.LENGTH_LONG).show();
if (referringParams.has(BundleExtraKeys.CLICKED_BRANCH_LINK)) {
try {
boolean clickedBranchLink = referringParams.getBoolean(BundleExtraKeys.CLICKED_BRANCH_LINK);
if (clickedBranchLink) {
//do stuff!
}
} catch (JSONException e) {
Log.d("BranchTrends", e.getMessage());
}
}
} else {
Log.i("MyApp", error.getMessage());
}
}
}, this.getIntent().getData(), this);
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context_ = this;
setContentView(R.layout.activity_main);
webView_ = (WebView) findViewById(R.id.webView);
webView_.setWebViewClient(new BranchWebViewController("app.link", MainActivity.class));
webView_.loadUrl(URL_TO_LOAD);
button_ = (Button) findViewById(R.id.button);
button_.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.intent.putExtra("branch", BRANCH_LINK_TO_LOAD);
customTabsIntent.intent.putExtra("branch_force_new_session", true);
finish();
customTabsIntent.launchUrl(MainActivity.this, Uri.parse(BRANCH_LINK_TO_LOAD));
}
});
}
public class BranchWebViewController extends WebViewClient {
private String myDomain_;
private Class activityToLaunch_;
BranchWebViewController(#NonNull String myDomain, Class activityToLaunch) {
myDomain_ = myDomain;
activityToLaunch_ = activityToLaunch;
}
#Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (url.contains(myDomain_)) {
Intent i = new Intent(view.getContext(), activityToLaunch_);
i.putExtra("branch", url);
i.putExtra("branch_force_new_session", true);
finish();
startActivity(i);
} else {
view.loadUrl(url);
}
return true;
}
}
}
Once you read the link parameters you can route to the appropriate Activity based on the link parameters.

Browser filed link click event [duplicate]

I am trying to handle an event in BrowserField when the user actually clicks a link.
I studied BrowserFieldListener, tried its documentCreated() method but that gives me a response when the page starts loading. I want a trigger the moment user clicks a link inside browserField.
What am i missing here?
Override handleNavigationRequest() of ProtocolController like
ProtocolController controller = new ProtocolController(browserField) {
public void handleNavigationRequest(BrowserFieldRequest request) throws Exception {
/*
Here you get the redirection link using
request.getURL()
and do what you want to do
*/
// to display url in browserfield use
InputConnection inputConnection = handleResourceRequest(request);
browserField.displayContent(inputConnection, request.getURL());
}
};
browserField.getConfig().setProperty(BrowserFieldConfig.CONTROLLER, controller);
Use the following class that was I used
public class CacheProtocolController extends ProtocolController{
public CacheProtocolController() {
super(browserField);
}
/**
* Handle navigation requests (e.g., link clicks)
*/
public void handleNavigationRequest(final BrowserFieldRequest request) throws Exception {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
// TODO Auto-generated method stub
Logger.debug("*******URL*******",request.getURL() );
});
}
/**
* Handle resource request (e.g., images, external css/javascript resources)
*/
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception {
return super.handleResourceRequest(request);
}
}
I have solved this problem using the following class:
public class CacheProtocolController extends ProtocolController{
private SparseList sparseList = null;
private int imageIndex ;
private int click = 0;
private BrowserField browserField = null;
public CacheProtocolController(BrowserField browserField,SparseList sparseList,int imageIndex ) {
super(browserField);
this.sparseList = sparseList;
this.imageIndex = imageIndex;
}
/**
* Handle navigation requests (e.g., link clicks)
*/
public void handleNavigationRequest(final BrowserFieldRequest request) throws Exception {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
Logger.debug("*******URL*******",request.getURL() );
String requestUrl = null;
requestUrl = FileManipulations.replaceAll(request.getURL(), "file:///SDCard/BlackBerry/pictures/", "../");
Logger.debug("*******requestUrl*******",requestUrl );
Enumeration enumeration = sparseList.elements();
while (enumeration.hasMoreElements()) {
final News news = (News) enumeration.nextElement();
if(news.getDetailsURL().equalsIgnoreCase(requestUrl)){
if(click == 1){
click = 0;
UiApplication.getUiApplication().pushScreen(new DetailedNewsScreen(news.getImageURL() , imageIndex));
} else
click++;
}
}
}
});
}
/**
* Handle resource request (e.g., images, external css/javascript resources)
*/
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception {
return super.handleResourceRequest(request);
}
}
And in the MainScren use the following
browserField = new BrowserField();
browserField.getConfig().setProperty(BrowserFieldConfig.CONTROLLER, new CacheProtocolController(browserField,List,index));

Blackberry 5.0 - BrowserField handle link clicked

I am trying to handle an event in BrowserField when the user actually clicks a link.
I studied BrowserFieldListener, tried its documentCreated() method but that gives me a response when the page starts loading. I want a trigger the moment user clicks a link inside browserField.
What am i missing here?
Override handleNavigationRequest() of ProtocolController like
ProtocolController controller = new ProtocolController(browserField) {
public void handleNavigationRequest(BrowserFieldRequest request) throws Exception {
/*
Here you get the redirection link using
request.getURL()
and do what you want to do
*/
// to display url in browserfield use
InputConnection inputConnection = handleResourceRequest(request);
browserField.displayContent(inputConnection, request.getURL());
}
};
browserField.getConfig().setProperty(BrowserFieldConfig.CONTROLLER, controller);
Use the following class that was I used
public class CacheProtocolController extends ProtocolController{
public CacheProtocolController() {
super(browserField);
}
/**
* Handle navigation requests (e.g., link clicks)
*/
public void handleNavigationRequest(final BrowserFieldRequest request) throws Exception {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
// TODO Auto-generated method stub
Logger.debug("*******URL*******",request.getURL() );
});
}
/**
* Handle resource request (e.g., images, external css/javascript resources)
*/
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception {
return super.handleResourceRequest(request);
}
}
I have solved this problem using the following class:
public class CacheProtocolController extends ProtocolController{
private SparseList sparseList = null;
private int imageIndex ;
private int click = 0;
private BrowserField browserField = null;
public CacheProtocolController(BrowserField browserField,SparseList sparseList,int imageIndex ) {
super(browserField);
this.sparseList = sparseList;
this.imageIndex = imageIndex;
}
/**
* Handle navigation requests (e.g., link clicks)
*/
public void handleNavigationRequest(final BrowserFieldRequest request) throws Exception {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
Logger.debug("*******URL*******",request.getURL() );
String requestUrl = null;
requestUrl = FileManipulations.replaceAll(request.getURL(), "file:///SDCard/BlackBerry/pictures/", "../");
Logger.debug("*******requestUrl*******",requestUrl );
Enumeration enumeration = sparseList.elements();
while (enumeration.hasMoreElements()) {
final News news = (News) enumeration.nextElement();
if(news.getDetailsURL().equalsIgnoreCase(requestUrl)){
if(click == 1){
click = 0;
UiApplication.getUiApplication().pushScreen(new DetailedNewsScreen(news.getImageURL() , imageIndex));
} else
click++;
}
}
}
});
}
/**
* Handle resource request (e.g., images, external css/javascript resources)
*/
public InputConnection handleResourceRequest(BrowserFieldRequest request) throws Exception {
return super.handleResourceRequest(request);
}
}
And in the MainScren use the following
browserField = new BrowserField();
browserField.getConfig().setProperty(BrowserFieldConfig.CONTROLLER, new CacheProtocolController(browserField,List,index));

How to push a new Screen when document is loaded in BrowserField?

In my application I have a log in Screen. When the user enter the correct user name and password I have to collect the information from the website and navigate to main Screen.
I tried following code. But this code is not working. How to achieve it?
public final class MyScreen extends MainScreen {
public MyScreen() {
BrowserFieldConfig myBrowserFieldConfig = new BrowserFieldConfig();
myBrowserFieldConfig.setProperty(BrowserFieldConfig.NAVIGATION_MODE,
BrowserFieldConfig.NAVIGATION_MODE_POINTER);
BrowserField browserField = new BrowserField(myBrowserFieldConfig);
BrowserFieldListener list = new BrowserFieldListener() {
public void documentLoaded(BrowserField browserField, Document document) throws Exception {
String url = document.getBaseURI();
String val = "http://demo.....";
//i am checking the correct url and i will navigate to main screen
if (url.equals(new String(val))) {
UiApplication.getUiApplication().pushScreen(new Main());//here i got IllegalStateException ..
}
System.out.println(" Login URL " + url);
//super.documentLoaded(browserField, document);
}
};
browserField.addListener(list);
add(browserField);
String URL = "http://demo.....";
if (DeviceInfo.isSimulator()) {
URL = URL + ";deviceSide=true";
}
browserField.requestContent(URL);
}
}
in place of
UiApplication.getUiApplication().pushScreen(new Main());
use
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
UiApplication.getUiApplication().pushScreen(new Main());
}
});
you need to do it under ui Thread.
Check it.

Blackberry BarcodeScanner - barcodeDecode switch to MainScreen

Can somebody tell me how to close the Screen (which opened by the BarcodeScanner) and show the mainscreen again after the barcodeDecoded method was invoked?
I can't get it right. I tried a lot, one of them was this:
public void barcodeDecoded(String rawText) {
final String result = rawText;
try
{
final UiApplication ui = UiApplication.getUiApplication();
final MainScreen current = (MainScreen) ui.getActiveScreen();
System.out.println("Current: " + current.toString());
if (UiApplication.isEventDispatchThread()) {
getText(result);
ui.popScreen(current);
System.out.println("Close Window by active screen");
ui.pushScreen(_frm);
System.out.println("Push screen frmMain");
}else{
ui.invokeLater(new Runnable() {
public void run() {
getText(result); <-- Abstract method to use within the main app.
ui.popScreen(current);
ui.pushScreen(_frm);
}
});
}
}catch(Exception err){
System.out.println(err.getMessage());
}
}
the abstract method when i start the Scanner
private MenuItem mnuCamera = new MenuItem("Scan", 1, 1){
public void run(){
frmMain f = (frmMain)getScreen();
_decode = new BarcodeDecoderClass(f) {
public void getText(String tekst) {
setScannedText(tekst);
}
};
_decode.Start();
}
};
Ok, for the people who are stuck with the same problem. I found it out. Below you find the complete code:
The BarcodeScanner class:
public abstract class BarcodeDecoderClass implements BarcodeDecoderListener {
private Hashtable _hints;
private Vector _formats;
private BarcodeScanner _scanner;
private BarcodeDecoder _decoder;
private Field _viewFinder;
private MainScreen _screen;
public abstract void getText(String tekst, Screen screen);
public BarcodeDecoderClass(){
_hints = new Hashtable();
_formats = new Vector();
_formats.addElement(BarcodeFormat.QR_CODE);
_hints.put(DecodeHintType.POSSIBLE_FORMATS, _formats);
_decoder = new BarcodeDecoder(_hints);
try
{
_scanner = new BarcodeScanner(_decoder, this);
_scanner.getVideoControl().setDisplayFullScreen(true);
_viewFinder = _scanner.getViewfinder();
}catch(Exception err){
System.out.println(err.getMessage());
}
}
public void Start(){
try
{
_screen = new MainScreen();
_screen.add(_viewFinder);
UiApplication.getUiApplication().pushScreen(_screen);
_scanner.startScan();
}catch(Exception err){
System.out.println(err.getMessage());
}
}
public synchronized void Close(){
if(_scanner.isScanning()){
try{
_scanner.stopScan();
}catch(Exception err){
Dialog.alert(err.getMessage());
}
}
_scanner.getVideoControl().setVisible(false);
_scanner.getPlayer().close();
}
public void barcodeDecoded(String rawText) {
try
{
getText(rawText, _screen);
}catch(Exception err){
System.out.println(err.getMessage());
}
}
}
The MainScreen from which I start the BarcodeScanner (i just copied the method)
private MenuItem mnuCamera = new MenuItem("Scan", 1, 1){
public void run(){
final Screen f = getScreen();
_decode = new BarcodeDecoderClass() {
public void getText(String tekst, final Screen _screen) {
setScannedText(tekst);
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_decode.Close();
_screen.close();
}
});
}
};
_decode.Start();
}
};
May be help full this code.
import java.util.Hashtable;
import java.util.Vector;
import net.rim.device.api.barcodelib.BarcodeDecoder;
import net.rim.device.api.barcodelib.BarcodeDecoderListener;
import net.rim.device.api.barcodelib.BarcodeScanner;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.FullScreen;
import net.rim.device.api.ui.container.MainScreen;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
public class BarcodeScanSample extends MainScreen{
private FullScreen _barcodeScreen;
private BarcodeScanner _scanner;
private LabelField lblBarcodeText;
private ButtonField btnScan;
public BarcodeScanSample(String barcodeText){
lblBarcodeText = new LabelField(barcodeText);
add(lblBarcodeText);
btnScan = new ButtonField("Scan");
btnScan.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
scanBarcode();
}
});
add(btnScan);
}
private void scanBarcode() {
// If we haven't scanned before, we will set up our barcode scanner
if (_barcodeScreen == null) {
// First we create a hashtable to hold all of the hints that we can
// give the API about how we want to scan a barcode to improve speed
// and accuracy.
Hashtable hints = new Hashtable();
// The first thing going in is a list of formats. We could look for
// more than one at a time, but it's much slower. and set Barcode Format.
Vector formats = new Vector();
formats.addElement(BarcodeFormat.QR_CODE);
formats.addElement(BarcodeFormat.CODE_128);
formats.addElement(BarcodeFormat.CODE_39);
formats.addElement(BarcodeFormat.DATAMATRIX);
formats.addElement(BarcodeFormat.EAN_13);
formats.addElement(BarcodeFormat.EAN_8);
formats.addElement(BarcodeFormat.ITF);
formats.addElement(BarcodeFormat.PDF417);
formats.addElement(BarcodeFormat.UPC_A);
formats.addElement(BarcodeFormat.UPC_E);
hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
// We will also use the "TRY_HARDER" flag to make sure we get an
// accurate scan
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
// We create a new decoder using those hints
BarcodeDecoder decoder = new BarcodeDecoder(hints);
// Finally we can create the actual scanner with a decoder and a
// listener that will handle the data stored in the barcode. We put
// that in our view screen to handle the display.
try {
_scanner = new BarcodeScanner(decoder, new MyBarcodeDecoderListener());
_barcodeScreen = new MyBarcodeScannerViewScreen(_scanner);
} catch (Exception e) {
System.out.println("Could not initialize barcode scanner: " + e);
return;
}
}
// If we get here, all the barcode scanning infrastructure should be set
// up, so all we have to do is start the scan and display the viewfinder
try {
_scanner.startScan();
UiApplication.getUiApplication().pushScreen(_barcodeScreen);
} catch (Exception e) {
System.out.println("Could not start scan: " + e);
}
}
/***
* MyBarcodeScannerViewScreen
* <p>
* This view screen is simply an extension of MainScreen that will hold our
* scanner's viewfinder, and handle cleanly stopping the scan if the user
* decides they want to abort via the back button.
*
* #author PBernhardt
*
*/
private class MyBarcodeScannerViewScreen extends MainScreen {
public MyBarcodeScannerViewScreen(BarcodeScanner scanner) {
super();
try {
// Get the viewfinder and add it to the screen
_scanner.getVideoControl().setDisplayFullScreen(true);
Field viewFinder = _scanner.getViewfinder();
this.add(viewFinder);
// Create and add our key listener to the screen
this.addKeyListener(new MyKeyListener());
} catch (Exception e) {
System.out.println("Error creating view screen: " + e);
}
}
/***
* MyKeyListener
* <p>
* This KeyListener will stop the current scan cleanly when the back
* button is pressed, and then pop the viewfinder off the stack.
*
* #author PBernhardt
*
*/
private class MyKeyListener implements KeyListener {
public boolean keyDown(int keycode, int time) {
// First convert the keycode into an actual key event, taking
// modifiers into account
int key = Keypad.key(keycode);
// From there we can compare against the escape key constant. If
// we get it, we stop the scan and pop this screen off the stack
if (key == Keypad.KEY_ESCAPE) {
try {
_scanner.stopScan();
} catch (Exception e) {
System.out.println("Error stopping scan: " + e);
}
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen(_barcodeScreen);
}
});
return true;
}
// Otherwise, we'll return false so as not to consume the
// keyDown event
return false;
}
// We will only act on the keyDown event
public boolean keyChar(char key, int status, int time) {
return false;
}
public boolean keyRepeat(int keycode, int time) {
return false;
}
public boolean keyStatus(int keycode, int time) {
return false;
}
public boolean keyUp(int keycode, int time) {
return false;
}
}
}
/***
* MyBarcodeDecoderListener
* <p>
* This BarcodeDecoverListener implementation tries to open any data encoded
* in a barcode in the browser.
*
* #author PBernhardt
*
**/
private class MyBarcodeDecoderListener implements BarcodeDecoderListener {
public void barcodeDecoded(final String rawText) {
// First pop the viewfinder screen off of the stack so we can see
// the main app
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen(_barcodeScreen);
}
});
_barcodeScreen.invalidate();
//Display this barcode on LabelField on BarcodeScanSample MainScreen we can also set whatever field here.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
UiApplication.getUiApplication().popScreen();
UiApplication.getUiApplication().pushScreen(new BarcodeScanSample(rawText));
_barcodeScreen.close();
_barcodeScreen=null;
}
});
}
}
}

Resources