I'm using addJavascriptInterface within my Android application to allow JavaScript to invoke functions I've created in my native Java application.
This worked well in Android 2.1, however in Android 2.2 I receive the error message "Error calling method on NPObject!"
When I instrument the method call the internals of the native method are getting called, however the exception is being throw in JavaScript.
I was getting this exact error:
Uncaught Error: Error calling method on NPObject!
Turns out I was attempting to invoke a JavascriptInterface function from a webview like so:
AndroidJS.populateField(field);
and on the Java side, the function didn't accept a parameter:
public void populateField() {}
Simply allowing the Java function to accept a parameter solved this error for me.
E.g.,
public void populateField(String field) {}
This may not be, and probably is not, the only reason this error could be thrown. This is simply how I resolved my specific scenario. Hope this helps! :)
OK, I have same problem as well, just in today.
What I did is putting code in UI Thread, like code below :
/**
* 給網頁Javascript呼叫的method
* Method for Javascript in HTML
* #param java.lang.String - Playlist ID
*/
public int callListByPID(final String pId)
{
Log.i(Constants.TAG, "PAD Playlist ID from HTML: "+pId);
runOnUiThread(new Runnable()
{
public void run()
{
// Put your code here...
}
});
return 1;
}
This solved my problem, and hope it can help some body... :-)
In my experience this problem is caused by Javascript interfaces bringing back objects that Javascript doesn't automatically identify.
In Android this is caused by wrappers like Boolean or Long in comparison to their native versions boolean and long.
//This will fail
public Long getmyLongVal() {
return 123456789;
}
//This will work
public long getMyNativeLongVal() {
return 123456789;
}
So remove your wrapper classes to any methods being used by Javascript if you want to avoid NPObject errors.
Here's a twist I found on this problem that could be useful for some of the folks running into this problem (and it likely explains intermittent failures that seem to defy explanation)...
If any exceptions are thrown (and not caught) in the return handler code prior to allowing the javascript interface callback to return clean, it will propagate back as a failed call and you will also get this error - and it would have nothing to do with missing functions or parameters.
The easiest way to find this case (whether or not you use this in your final implementation) is to push whatever handler code you have back onto the UI thread (the callback will not be on the UI thread) - this will allow the callback to return clean and any subsequent exceptions that occur will propagate properly up until you catch them or until the app crashes. Either way you will see exactly what is really happening. Otherwise the uncaught exception passes back to javascript where it will not be handled or reported in any way (unless you specifically built error trapping code into the JS you were executing).
Good Luck All.
bh
I had the same problem with Javascript-to-Java interface (WebView.addJavascriptInterface).
In Android 2.1 everything worked just fine but in Android 2.2 Javascript failed to call methods from this interface. It returned an error: Uncaught Error: Error calling method on NPObject!
It seems that on Android 2.2, the WebView has problem with Boolean data type returned from interface functions.
Changing:
public Boolean test_func() { return true; }
... to:
public int test_func() { return 1; }
... solved the problem.
This I believe is no longer supported anymore ( Always game NPObject error ) .
Please refer to the answer in this thread
Visit open an activity from a CordovaPlugin
Related
My app consist of Fragments with fullscreen WebView. When user click on a link in the WebView then is opened new Fragment with new WebView with the same URL. Before open new Fragment I close soft keyboard just in case. I open new page very quick. All operations perform on the main thread.
By the Crashlytics the problem appers only on the Android 10 (all Pixel-series devices and other devices with 10).
On devices before Android 10 all works fine. I can open much Fragments. But on Android 10 devices this case leads to FATAL EXCEPTION (after 2-3 quick attempts to open new page, randomly):
E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-1
Process: <myapp>, PID: 12487
java.lang.RuntimeException: Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked.
at Yp.a(PG:13)
at com.android.webview.chromium.WebViewChromium.onCheckIsTextEditor(PG:4)
at android.webkit.WebView.onCheckIsTextEditor(WebView.java:3035)
at android.view.inputmethod.InputMethodManager.checkFocusNoStartInput(InputMethodManager.java:1901)
at android.view.inputmethod.InputMethodManager.checkFocus(InputMethodManager.java:1863)
at android.view.inputmethod.InputMethodManager.hideSoftInputFromWindow(InputMethodManager.java:1506)
at android.view.inputmethod.InputMethodManager.hideSoftInputFromWindow(InputMethodManager.java:1475)
at <myapp>.Utils.hideKeyboard(Utils.java:175)
at <myapp>.openNewPage(Pager.java:210)
...
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:206)
at Yp.a(PG:11)
I tried to use all available versions of the Android System WebView (stable, beta, dev, canary) but nothing to help.
Anybody can help me?
Update:
If I comment code for hiding soft keyboard then all works fine.
This is not solution, only explain the issue.
First, you said "All operations perform on the main thread.", but it is wrong.
The stack trees has indicated it is in a Worker thread.
And it is also can be confirmed from source code.
WebView's blocking task.
Second, the code changed in Android Q, which checks view is text editor from this version.
Third, you post one task using View.post(). It is in UI thread, and the process is different in WebView (That is, it needn't wait and block)
In summary, InputMethodManager starts a task (WebView.onCheckIsTextEditor()) in non-UI thread, and WebView wants do it in UI thread, but it don't get result for timeout(4 seconds).
So it is because you have too much work in the UI thread
I think this is not the correct way to solve this problem, but it should work around this problem by extending WebView class and overriding onCheckIsTextEditor() method:
#Override
public boolean onCheckIsTextEditor() {
try {
return super.onCheckIsTextEditor();
} catch (Throwable th) {
// Probable deadlock detected due to WebView API being called on incorrect thread while the UI thread is blocked.
return true; // or return false in your scenario.
}
}
I have found a solution but not sure that it's correct. If anybody know the reason this crash or more elegant solution I'll be grateful.
Solution: wrap hideSoftInputFromWindow() in the View.post():
public static void hideKeyboard(#NotNull Context context, #NotNull View view, int flags) {
view.post(() ->
((InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(view.getWindowToken(), flags));
}
I faced this problem for a react-native project on Android 10 with the package react-native-webview. I added a workaround for this problem to file RNCWebViewManager.java.
import android.os.Looper;
...
protected static class RNCWebView extends WebView implements LifecycleEventListener {
....
#Override
public boolean onCheckIsTextEditor() {
if (Looper.myLooper() == Looper.getMainLooper()) {
return super.onCheckIsTextEditor();
} else {
return false;
}
}
}
code screenshot
I'm trying to add a BackdoorMethod to a Xamarin.Forms application to bypass the login (IDP - opened in chrome browser) step. I have the feeling that the method is not getting triggered, but not sure, and I don't know how could I make sure about it.
I've read the documentation here: https://learn.microsoft.com/en-us/appcenter/test-cloud/uitest/working-with-backdoors
Check this thread: https://forums.xamarin.com/discussion/85821/xamarin-uitest-backdoor-on-droid-with-splash-screen-how-do-i-access-my-mainactivity
Checked this example: https://github.com/brminnick/UITestSampleApp/tree/master/Src
In the MainActivity.cs file I've defined the BackdoorMethod:
[Preserve, Export(nameof(BypassLoginScreen))]
public string BypassLoginScreen()
{
// some additional code here. the code is working, when I called it
// directly from OnCreate it was executed without any error
return "called";
}
From the test case i'm trying to invoke it like:
public constructorMethod(Platform platform)
{
this.platform = platform;
app = AppInitializer.StartApp(platform);
var result = app.Invoke("BypassLoginScreen"); // result == "<VOID>"
}
I'm not getting any error message, the method simply not called, or not returns anything. (or i don't know what's happening there with it, because breakpoint also not working as the app started from the device)
This should be already working. I have similar code and it works for me.
you can add inside your function
Android.Util.Log.WriteLine(Android.Util.LogPriority.Info, "BypassLoginScreen", $"Some text as info");
And observe the result in Device Logs, Filter by BypassLoginScreen to see if there is any log created with the tag BypassLoginScreen
I found this bit of code in one of the example tango projects using the JNI and I have no idea what the context is nor how to use it. The example code works, but my code does not.
void OnXYZijAvailableRouter(void *context, const TangoXYZij *xyz_ij) {
SynchronizationApplication *app =
static_cast<SynchronizationApplication *>(context);
app->OnXYZijAvailable(xyz_ij);
}
I tried mimicking it below:
void OnFrameAvailableRouter(void *context, const TangoCameraId id,
const TangoImageBuffer *buffer) {
SynchronizationApplication *app =
static_cast<SynchronizationApplication *>(context);
LOGE("Before onframe call.");
app->onFrameAvailable(id, buffer);
LOGE("After onframe call.");
}
When I try to run it, however, I get this output:
Before onframe call.
Fatal signal 11 (SIGSEGV) at 0x00000308 (code=1), thread 15673 (Binder_2)
Now I managed to find the pointer that causes the seg fault, but I have no idea why it does not work.
Naturally, I might have done something wrong, but I have no idea what since I made an exact copy of the code in the example.
int SynchronizationApplication::TangoConnectCallbacks() {
TangoErrorType depth_ret =
TangoService_connectOnXYZijAvailable(OnXYZijAvailableRouter);
depth_ret = TangoService_connectOnFrameAvailable(TangoCameraId::TANGO_CAMERA_COLOR, NULL,
OnFrameAvailableRouter);
return depth_ret;
}
The functions I call from the routers.
void OnXYZijAvailable(const TangoXYZij *xyz_ij);
void onFrameAvailable(const TangoCameraId id, const TangoImageBuffer *buffer);
What exactly is the context? I have read some explanations, but I still do not understand why I can call the function using the context in the example above, nor why I need the router function at all. I have read this SO answer and the android page on the concept, but I see no link between the context and my class.
In the OnXYZijAvailableRouter (the depth callback), the context is the instance passed in from the TangoService_connect function. I believe in the application class, there should be a line like this: TangoService_connect(this, tango_config_); So this become the context when the callback is called. This context also applies to pose and event callbacks.
In the case of OnFrameAvailableRouter, the context is the instance you passed in in the TangoService_connectOnFrameAvailable. In this case, the code is setting a NULL as context, but in the callback, it's trying the call a function on NULL. That's the crash point.
I believe if you change the it to TangoService_connectOnFrameAvailable(TangoCameraId::TANGO_CAMERA_COLOR, this, OnFrameAvailableRouter); it should work fine.
The router function is for the callbacks, I haven't find a way of giving a function pointer of a instance to the API. But let me know if you find a way to do that, I would like to know as well..
I am developing on a library that is somehow getting a CalledFromWrongThread Exception crash on Samsung Galaxy S1 (api v7 - android 2.1). The code is something like this:
class MyWebViewClient extends WebViewClient {
#Override
public void shouldOverrideUrlLoading(WebView view, String url) {
someListener.addToUiView();
}
}
and of course, the method that is actually throwing the error (which implements a listener callback):
View v;
public void addToUiView(){
v.addView(new TextView(context)); //<-- this line is throwing the error on rare occasions
}
I'm skipping some code in between, but i'm not doing anything weird in other places. Also note: this crash only seems to have been happening a very very small % of the time. (not necessarily conclusive, as not everyone reports their data).
has anyone else come across this?? Is WebCore threading messing things up?
Now I haven't actually tested this but I am going to answer to the best of my knowledge. That said, my instinct is telling me that you are only seeing the error intermittently because web requests from a WebView (browser) happen with varying levels of asynchronicity and probably utilize a thread pool to accomplish this. Basically, sometimes it requests resources in parallel and sometimes it doesn't. Worse yet you might be seeing this error on only a single device because OEMs optimize OS level code (like the WebView internals) based on their preferences and opinions (especially Samsung). Either way the real problem is that you are doing something "UI related" in a place that is definitely not guaranteed to be "UI friendly"... That is, anywhere where you are getting a subsystem callback.
The solution to your problem is much more simpler than the explanation: just use your context (that I am assuming is an Activity)..
Activitys have a built in function called runOnUiThread(Runnable) that will guard the code inside the runnable from running on the wrong thread. Basically, your problem is really common and android has a built-in solution. runOnUiThread will only add overhead if required, in other words if your thread is the UI thread, it will just run the Runnable, if it isn't it uses the correct Handler (the one associated with the UI thread) to run the Runnable.
Here is what it should look like:
View v;
public void addToUiView() {
final Activity activity = (Activity) context;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
v.addView(new TextView(activity));
}
});
}
i coded that up right inside the SO window so my apologies for any egregious errors, I hope that helps, and let me know if you need more info or of this doesn't solve your problem -ck
Is it possible to have something like this? Either with Android/Robotium test frameworks or any other solutions
public void testAll() throws Exception {
test_001_LoginActivity();
test_002_MainActivity();
}
public void test_001_LoginActivity() throws Exception {
startActivity();
test_001_LoginActivity_001_emptyUsername();
test_001_LoginActivity_002_emptyPassword();
test_001_LoginActivity_003_incorrectValues();
test_001_LoginActivity_004_correctValues(); // MainActivity is opened on success
}
public void test_002_MainActivity() throws Exception {
test_002_MainActivity_001_profile();
test_002_MainActivity_002_list();
test_002_MainActivity_003_logout();
}
The idea is to have test_001_LoginActivity() and test_002_MainActivity()contain all the corresponding activity test without recreation of the activities. And to have a result displayed like that:
test_001_LoginActivity() - OK
--->test_001_LoginActivity_001_emptyUsername() - OK
--->test_001_LoginActivity_002_emptyPassword() - OK
--->test_001_LoginActivity_003_incorrectValues() - OK
--->test_001_LoginActivity_004_correctValues() - OK
test_002_MainActivity() - NOK
--->test_002_MainActivity_001_profile() - OK
--->test_002_MainActivity_002_list() - NOK
--->test_002_MainActivity_003_logout() - OK
Which means that all tests for LoginActivity are passed successfully; test_002_MainActivity_002_list() test failed for MainActivity, but test_002_MainActivity_003_logout() test was passed(since activity was not recreated)
I'm new to testing, so maybe I'm getting it wrong and tests are intended to be executed for a brand new activity instance always?
What your are trying to do might be possible if you rename all test_00X_METHOD methods becuase currently it will go to total mess because "test" prefix before a methods has a special meaning for jUnit Framework - beside all will be executed by you from testAll() also all methods will be executed latere seperately as jUnit run all methods with "test" prefix as seperate test case and application is even restarted between those methods. So it should works fine if you throw away all "test" prefixes but keep it for testAll(). And you needn't "startActivity()" method at the begining of test_001_LoginActivity() because Activity is automaticaly started - which activity? Activity you passed as type parameter to this class: http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html.
I hope this answer is useful for you.
Krzysiek,
Bitbar Software Engineer