I am working on an e-learning project using SCROM APIs, but now I got stuck at one point: how to get server-side JavaScript value in my core Android activity IN WEBVIEW from scrom API?
I am trying below code:
public class MyJavaScriptInterface
{ Context mContext;
/** Instantiate the interface and set the context */
MyJavaScriptInterface(Context c) {
mContext = c;
}
/** retrieve the ids */
public void getbookmark(final String bookmarkId) {
webView.loadUrl("javascript:Android.getbookmark(BOOKMARKED_PAGE);");
//getWindow().requestFeature();
}
#SuppressWarnings("unused")
public void showHTML(String html)
{
new AlertDialog.Builder(myApp)
.setTitle("HTML")
.setMessage(html)
.setPositiveButton(android.R.string.ok, null)
.setCancelable(false)
.create()
.show();
}
}
Do I have to take the value of onpagefinished() function of WebView?
You'll want to add a javascript interface:
mWebView.addJavascriptInterface(new MyJavaScriptInterface(getApplicationContent(), "JSInterface");
Add a method in your interface you want to call and ensure you have the #JavascriptInterface annotation so Android makes it callable:
#JavascriptInterface
public void showHTML(String html)
{
new AlertDialog.Builder(myApp)
.setTitle("HTML")
.setMessage(html)
.setPositiveButton(android.R.string.ok, null)
.setCancelable(false)
.create()
.show();
}
Then follow the approach you are doing at the moment of calling a method in javascript:
webView.loadUrl("javascript:Android.getbookmark(BOOKMARKED_PAGE);");
And the javascript method would look something like:
window.Android.getbookmark = function(variable) {
var returnValue = getSomeValue(variable);
if(!window.JSInterface) {
console.error('window.JSInterface not defined - Did you inject the javascript interface in the native app?');
}
window.JSInterface.showHTML(returnValue);
};
Notice the reason we have window.JSInterface is because we added it with that name in:
mWebView.addJavascriptInterface(new MyJavaScriptInterface(getApplicationContent(), "JSInterface");
NOTE: In KitKat it is more efficient to use evaluateJavascript() than loadUrl, simplest form shown below, allow you can pass in a callback to get a return value (Demo in the sample code)
webView.evaluateJavascript("Android.getbookmark(BOOKMARKED_PAGE);", null);
There is a full JS Interface sample here which includes the new API's in KitKat: https://github.com/GoogleChrome/chromium-webview-samples
you can use javascript bridge for your requirement
you can find the source , this too
Related
I try to do list of usb devices, connected by serial odt with smartphone, within xamarin.forms.
To do that I use this project https://github.com/anotherlab/UsbSerialForAndroid
How to do listview in shared project with devices from Project.Droid.MainActivity? I tried to do that with dependency service:
This is my Page1(where I want to have listview):
public partial class Page1 : ContentPage {
public Page1()
{
InitializeComponent();
DependencyService.Get<Interface1>().moj();
}
}
My interface:
namespace SensDxMobileApp.Views.MainWindow {
public interface Interface1 {
void moj();
}
}
And MyActivity(Droid project):
[assembly: Xamarin.Forms.Dependency(typeofProject.Droid.MainActivity))]
namespace Project.Droid {
public class MainActivity: Interface
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
listView = new Android.Widget.ListView;
}
public async void moj()
{
adapter = new UsbSerialPortAdapter(this);
listview.Adapter = adapter;
listView.ItemClick += async (sender, e) =>
{
await OnItemClick(sender, e);
};
await PopulateListAsync();
detachedReceiver = new UsbDeviceDetachedReceiver(this);
RegisterReceiver(detachedReceiver, new IntentFilter(UsbManager.ActionUsbDeviceDetached));
}
}
But I have an error "Object reference not set to an instance of an object.", on " DependencyService.Get().moj()" in Page1();
Did someone do something similar? Thanks
If you going the DependencyService route, then you'll want to create a separate class that implements Interface1 and registering that as a dependency service. I don't think you can register the MainActivity as a DependencyService implementation.
One problem that you are going to hit this is mostly async code and callbacks.
You also shouldn't be newing up an Android ListView as a DependencyService call. That would be better suited as a custom renderer. As a DependencyService implementation, you would want the moj() method to return data that can be consumed by the Xamarin.Forms code. You would need more than just that method. You would need code to initialize the UsbSerialPort class, code to query the list of devices, and then invoke a callback that sends back that list, In theory anyway. I never tested that library with Forms.
Android injects a JS interface into a web view:
JavaScriptInterface javaScriptInterface = new JavaScriptInterface(this);
browser.addJavascriptInterface(javaScriptInterface, "qp");
The interface looks like this:
public class JavaScriptInterface {
private ILoadEpi iLoadEpi;
public JavaScriptInterface(ILoadEpi iLoadEpi) {
this.iLoadEpi = iLoadEpi;
}
#JavascriptInterface
public void passParameters(String fldMerchCode,
String fldMerchRefNbr,
String fldTxnAmt,
String fldTxnScAmt,
String fldDatTimeTxn,
String fldDate1,
String fldDate2
) {
Log.d("fldMerchCode", fldMerchCode);
Log.d("fldMerchRefNbr", fldMerchRefNbr);
Log.d("fldTxnAmt", fldTxnAmt);
Log.d("fldTxnScAmt", fldTxnScAmt);
Log.d("fldDatTimeTxn", fldDatTimeTxn);
Log.d("fldDate1", fldDate1);
Log.d("fldDate2", fldDate2);
iLoadEpi.loadEpi(fldMerchCode, fldMerchRefNbr, fldTxnAmt, fldTxnScAmt, fldDatTimeTxn, fldDate1, fldDate2);
}
}
How can a web app developed using TypeScript call this Android?
Or more broadly, how can a TypeScript application call an Android method?
Add a TypeScript definition for the JavaScriptInterface type that will be injected by Android. Then declare a variable with the name of the instance injected by Android, then use it as normal. In your example, the definition you need is:
interface JavaScriptInterface {
passParameters(fldMerchCode: string,
fldMerchRefNbr: string,
fldTxnAmt: string,
fldTxnScAmt: string,
fldDatTimeTxn: string,
fldDate1: string,
fldDate2: string) : void;
}
declare var qp: JavaScriptInterface;
The qp instance injected by Android will have the method passParameters available on it. The instance is created by Android with the name qp in your call to browser.addJavaScriptInterface(javaScriptInterface, "qp");. Note that, depending on how your passParameters function is used, you may need to declare the return type as any instead of void.
Here's a complete example based on the Android guide for binding JS:
In your HTML file, add:
<input type="button" value="Say hello" id ="button"/>
<script src="./generated/bundle.js"></script>
where I assume that your generated/transpiled JavaScript is located at ./generated/bundle.js, relative to the HTML file.
In your TypeScript file, add:
interface WebAppInterface {
showToast(toast: string) : any;
}
declare var android: WebAppInterface;
var button = document.getElementById('button');
button.onclick = ()=>android.showToast('Hello Android!');
Note that the linked Android example names the injected object android:
webView.addJavascriptInterface(new WebAppInterface(this), "android");
And in case the linked example changes or disappears, here is the example WebAppInterface.java:
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
My application has a webview calling an url and basically all the stuff will be done by the website, but after the user finishes the proccess, it will send an information for the app, like success or invalid.
I want to know how to catch this return value through the webview. Is there a way to do this?
thanks.
You should use a JavascriptInterface to expose one of your Java methods to Javascript on your website.
First, create a class to act as your interface. Any methods you want to expose to Javascript need the #JavascriptInterface annotation:
class MyJavaScriptInterface{
#JavascriptInterface
public void myMethod(boolean success){
//Do something with value
}
}
Then initialize the interface on your WebView:
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new MyJavaScriptInterface(), "JSInterface");
Finally, create the Javascript function to call the Java method from your website:
<script>
//Communicate with Javascript Interface
var processComplete = function(success){
//Only call if the interface exists
if(window.JSInterface){
window.JSInterface.myMethod(success);
}
};
</script>
I am currently developing an application using Xamarin.Forms that will be available on the Android and iOS platforms. When the application is first loaded on device, I check to see if there is an internet connection available on the device. I want to display a dialog box if an internet connection is not available.
Here is the following snippet of code I am using to check the internet on the Xamarin.Forms.ContentPage
if(App.Connectivity.IsNetworkConnectivityAvailable())
{
App.Notification.DisplayLocalNotifications("No Internet", "You need an internet connection to access certain application content");
}
I am using dependency injection to build the appropriate module for handling dialog boxes for each appropriate environment. The Android is throwing the following exception
Android.Views.WindowManagerBadTokenException: Unable to add window --
token null is not for an application Here is the code for the
DisplayLocalNotification method on the Android:
public void DisplayLocalNotification(string title, string content)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Application.Context)
.SetTitle(title)
.SetMessage(content)
.SetCancelable(true)
.SetPositiveButton("OK", (EventHandler<DialogClickEventArgs>) null);
AlertDialog alert = builder.Create();
alert.Show();
var okBtn = alert.GetButton((int)DialogButtonType.Positive);
okBtn.Click += (sender, args) =>
{
alert.Dismiss();
};
}
After doing some research, I need to get pass the current activity to the AlertDialog.Builder constructor instead of the Application.Context. How do I get the current activity object from the application context when you need to the activity outside of the activity context?
Xamarin.Forms Android platform code should assign the current Activity into Forms.Context property. This is the static Forms class and if you debug it you will see that the Forms.Context is an Activity.
public static class Forms
{
public static Context Context { get; }
public static bool IsInitialized { get; }
public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
public static void Init(Activity activity, Bundle bundle);
}
I am developing a webview in which i have to define the type of object when i click to this object. For example, when i click to a link, webview understand it is a link and i can get link (returned object); when i click to a image, webview understand it is a image and return image object. I want to get the object type to do some more activities. For example, when i long click to the image, there are some action for me: download, set as background,... when i long click to a link, there are some option like: open in new tab, add to bookmark,... Does anyone know the solution. Thank u very much :)
I think that you cannot have direct visibility to the "downside" html/javasctipt from webview listeners.
(WebView reference here: http://developer.android.com/reference/android/webkit/WebView.html)
However, if you are developing the web application running in the WebView, you can obtain the same result by using JavascriptInterface methods, implementing the javascript methods to "upside" return objects toward android app.
Example interface class:
public class JSUpInterface {
protected Context mContext;
public JSUpInterface(Context c) {
mContext = c;
}
#JavascriptInterface
public void showToast(String message) {
Toast.makeText(mContext, message, Toast.LENGTH_SHORT).show();
}
#JavascriptInterface
public void getLink(String link) {
// shows in a toast the clicked link
Toast.makeText(mContext, link, Toast.LENGTH_SHORT).show();
}
}
WebView attaching:
jsUi = new JSUpInterface(context);
webview.addJavascriptInterface(jsUi, "jsui");
your html:
www.google.com