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
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.
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));
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));
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.
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;
}
});
}
}
}