Android AspectJ #Around with method args not working - android

In my current Android application I am investigating the use of #AspectJ
I am attempting to "capture" all executions to methods whose signature resembles:-
public void onMethodClicked(com.example.CustomType customType) {}
I have the following POINTCUTS
1) Ignore my Aspect class:
#Pointcut("!within(com.example.aspect)")
public void notAspect() { }
2) Select all "Clicked" methods with customType argument
#Pointcut("execution(* com.example..*.*Clicked(com.example.CustomType)) && args(custom)";)
public void customClicked(CustomType custom) { }
3) My #Around:-
#Around("notAspect() && customClicked()")
public Object selectedClicked(final ProceedingJoinPoint joinPoint, CustomType custom) throws Throwable {
Log.d(TAG, "Found a clicked method " + custom);
Object result = joinPoint.proceed();
return result;
}
When I build my Android Application I get these messages
no match for this type name: CustomType [Xlint:invalidAbsoluteTypeName]
bad parameter to pointcut reference
formal unbound in pointcut
no match for this type name: com.example.aspect [Xlint:invalidAbsoluteTypeName]
the parameter custom is not bound in [all branches of] pointcut
use of ProceedingJoinPoint is allowed only on around advice (arg 1 in (before(extraFlags: 2): (((!within(com.example.aspect+) && execution(* com.example..*.*Clicked(com.example.CustomType)) && args(custom)) && persingleton(com.example.aspect.TraceAspect))->void com.example.aspect.TraceAspect.selectedClicked(org.aspectj.lang.JoinPoint, com.example.CustomType)))
What have I done wrong?
UPDATE
I have fixed one of the error/warning messages by correcting the !within() as follows:-
1) Ignore my Aspect class:
#Pointcut("!within(com.example.aspect.TraceAspect)")
public void notAspect() { }

I'm not sure about your problem but you may try changing the POINTCUT like this.
#Pointcut("!within(com.example.aspect.TraceAspect)")
public void notAspect() { }
#Pointcut("execution(* com.example..*.*Clicked(com.example.CustomType)))
public void customClicked() { }
Look I've removed the args(custom) part here which go inside the #Around annotation. And yes, of course I've removed the function parameter argument of customClicked function and the semi-colon by the end of the statement.
Now write your selectedClicked function like this by passing the arguments from here.
#Around("notAspect() && customClicked() && args(custom)")
public Object selectedClicked(final ProceedingJoinPoint joinPoint, CustomType custom) throws Throwable {
Log.d(TAG, "Found a clicked method " + custom);
Object result = joinPoint.proceed();
return result;
}
It should work with no failure.

Related

How can I run Dart code from the android part(Kotlin code) of my project?[FLUTTER] [duplicate]

I am writing a native plugin that, in some cases, has to call functions in the Flutter portion of the app, written in Dart.
How it's achieved, is explained here:
https://flutter.io/platform-channels/
Furthermore, an example of invoking a method from the native/platform part towards the Dart/non-native is here:
https://github.com/flutter/plugins/tree/master/packages/quick_actions
Now, this example is really nice in case the platform only needs to invoke a method, i.e. that call returns nothing/void, but in case it needs to invoke a function, i.e. needs a return value from the non-native/Dart part, I could not have found an example or documentation on the internet. I believe it can be implemented though, because in the native Java part, there is a method:
public void invokeMethod(String method, Object arguments, MethodChannel.Result callback)
So, there is a callback object that could have a return value from the non-native part - or, I am mistaken here, and there is currently no way of returning a value from the non-native Dart portion of the app?
The signature is void setMethodCallHandler(Future<dynamic> handler(MethodCall call)), so we need to provide a function at the Dart end that returns Future<dynamic>, for example _channel.setMethodCallHandler(myUtilsHandler);
Then implement the handler. This one handles two methods foo and bar returning respectively String and double.
Future<dynamic> myUtilsHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case 'foo':
return 'some string';
case 'bar':
return 123.0;
default:
throw MissingPluginException('notImplemented');
}
}
At the Java end the return value is passed to the success method of the Result callback.
channel.invokeMethod("foo", arguments, new Result() {
#Override
public void success(Object o) {
// this will be called with o = "some string"
}
#Override
public void error(String s, String s1, Object o) {}
#Override
public void notImplemented() {}
});
In Swift, the return value is an Any? passed to the result closure. (Not implemented is signaled by the any parameter being the const NSObject value FlutterMethodNotImplemented.)
channel.invokeMethod("foo", arguments: args, result: {(r:Any?) -> () in
// this will be called with r = "some string" (or FlutterMethodNotImplemented)
})

Mockito thenReturn not working as expected

I'm having problem with mockito. I'm mocking a class and then using thenReturn() on on of its method. but seems like something is going wrong. here is the code.
TestCode:
public void getCardsTest() {
FeatureFragmentPresenterImpl presenter = new FeatureFragmentPresenterImpl();
GroupFeatureData data = Mockito.mock(GroupFeatureData.class);
FeatureFragmentView view = Mockito.mock(FeatureFragmentView.class);
presenter.init(view, data);
Observable<Response<ResponseBody>> errorObservable = Observable.error(new IOException());
assertNotNull(observable);
Mockito.when(data.getCards(Mockito.anyString(), Mockito.anyString(),
Mockito.anyInt(), Mockito.anyInt())).
thenReturn(errorObservable);
presenter.getAllCards(new Contact(new Name("ssd")), -1);
}
Presenter code :
public void getAllCards(IContact iContact, int lastIndex) {
Observable<Response<ResponseBody>> allCardsResponseObservable = mGroupFeatureData.getCards(path, id, 10, lastIndex);
allCardsResponseObservable
.subscribeOn(Schedulers.io()) -------> Test Failing because NPE here
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<Response<ResponseBody>>() {
#Override
public void onNext(#NonNull Response<ResponseBody> response) {
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
});
}
public void init(FeatureFragmentView featureFragmentView,
GroupFeatureData groupFeatureData) {
this.mGroupFeatureData = groupFeatureData;
this.mFeatureFragmentView = featureFragmentView;
}
Even though i'm mocking response of data.getCards() in Test, In presenter it is throwing NPE whereas it should just operate on mocked Observable that is errorObservable. what is going wrong here?
The NPE tells us that this line:
mGroupFeatureData.getCards(path, id, 10, lastIndex);
... returns null which implies that the actual method call and the method call which you mocked here ...
Mockito.when(data.getCards(Mockito.anyString(), Mockito.anyString(),
Mockito.anyInt(), Mockito.anyInt())).
thenReturn(errorObservable);
... do not match. The code supplied shows this actual call:
Observable<Response<ResponseBody>> allCardsResponseObservable =
mGroupFeatureData.getCards(path, id, 10, lastIndex);
Breaking this call down we can say that:
The third argument 10 is an int so this will match the given argument matcher: Mockito.anyInt()
The fourth argument lastIndex is declared as an int so this will match the given argument matcher: Mockito.anyInt()
The type of the first and second argments is not clear from your code extract since we do not see where path and id are declared but unless they are both of type String then the given argument matchers for these parameters (Mockito.anyString()) will not match and hence the mocked call will return null.
So, it looks to me like one or other of path and id are not actually of type String. It would be useful if you could update your question to show where these types are declared.

EventBus calling two different handlers for a single post

I am having problems with EventBus 3.0.0 where I post a single event like this:
Call<List<SessionSpec>> call = httpService.getSessionSpecs();
call.enqueue(new Callback<List<SessionSpec>>() {
#Override
public void onResponse(Call<List<SessionSpec>> call, Response<List<SessionSpec>> response) {
if (response.isSuccessful()) {
List<SessionSpec> specs = response.body();
EventBus.getDefault().post((List<SessionSpec>)specs);
}
else Log.e(TAG, "sendSessionSpecs(): request NOT successful");
}
#Override
public void onFailure(Call<List<SessionSpec>> call, Throwable t) {
Log.e(TAG, "sendSessionsSpecs(): failed");
}
});
I have two subscribers in the same fragment, each with different signatures, but they are both getting called from a single post:
#Subscribe
public void onSessionSpec(List<SessionSpec> specs) {
Log.d(TAG, "onSessionSpec(): entered");
Log.d(TAG, " : number of session specs: " + specs.size());
}
The second subscriber is defined as:
#Subscribe
public void onOverlayType(List<OverlayType> types) {
Log.d(TAG, "onOverlayType(): entered");
Log.d(TAG, " : number of overlay types: " + types.size());
}
Both of these callbacks are in a single fragment which is active when the post is done and I have verified that the post is only called once. When the single SessionSpec event is posted, both the onSessionSpec and the onOverlayType callbacks are dispatched by EventBus with the event type of List> so the onOverlayType callback receives the wrong type in its callback argument. The class OverlayType is a simple POJO class with 2 members, a int "sid" and a String "name". The class SessionSpec is more complex; it does have a member String "name" but other than that, nothing else is common between these 2 classes. I have verified that there is nothing closely resembling "OverlayType" in the SessionSpec class.
The interface definition is this:
public interface VcapHttpInterface {
#GET("overlay/types")
Call<List<OverlayType>> getOverlayTypes();
#GET("session/list")
Call<List<SessionSpec>> getSessionSpecs();
#GET("session/{id}")
Call<Session> getSession(#Path("id") int sid);
}
The getSession event post/callback has no problems.
I have spend all day trying to figure what is going wrong so I am clueless at this point. Anybody know what might be wrong with my code?
Thanks,
-Andres
Edit: How does EventBus know which handler to call for a particular response? Some posts I have read said that EventBus does not use the handler signature, but how else would it know how to map a response to the right subscribed handler routine? Is there a way to explicitly define the handler callback for a given event?
EventBus checks the class of the object that you are posting, and calls the methods that expect that class in their parameters. In your case you are posting an object which is a List. In both your listeners you expect an object of type List. It doesn't matter what generic you put in OverlayType or SessionSpec, eventbus will call both. In order to make it work you gotta define to models as events.
public class OverlayTypeEvent {
public List<OverlayType> types;
public OverlayTypeEvent(List<OverlayType> types) {
this.types = types;
}
}
and
public class SessionSpecEvent {
public List<SessionSpec> types;
public SessionSpecEvent(List<SessionSpec> types) {
this.types = types;
}
}
And listen on them seperatley. Then post events with the specific type.
#Subscribe
public void onSessionSpec(OverlayTypeEvent event) {
List<OverlayType> overlayTypes = event.overlayType;
}
If you don't want to create new class as a container everytime you send a list data, you can you Pair as simple container, it has two generic fields (first and second) to contain variables.
You can use first as a key to check the type of class, second contains the actually data.
List<SessionSpec> specs = response.body();
EventBus.getDefault().post(new Pair<>(SessionSpec.class.getSimpleName(), specs));
Receive data:
#Subscribe
public void onSessionSpec(Pair<String, List<SessionSpec>> specContainer){
if (SessionSpec.class.getSimpleName().equals(specContainer.first)) {
List<SessionSpec> sessionSpecs = specContainer.second;
}
}
#Subscribe
public void onOverlayType(Pair<String, List<OverlayType>> overlayContainer) {
if (OverlayType.class.getSimpleName().equals(overlayContainer.first)) {
List<OverlayType> overlayTypes = overlayContainer.second;
}
}
Advantage of this solution: Reduce creating unneeded classes.
Disadvantage: both onSessionSpec and onOverlayType get called.

How to reference an Activity from within an Aspect

I currently have the current aspect
#Aspect
public class ActivityShowingAspect {
private static final String POINTCUT_METHOD =
"execution(#nz.co.kevinsahandsomedevil.android.myaccount.aspect.ActivityMustBeShowing * *(..))";
#Pointcut(POINTCUT_METHOD)
public void methodAnnotatedWithActivityShowing() {
}
#Around("methodAnnotatedWithActivityShowing()")
public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
Activity activity = // code to retrieve the calling activity, joinPoint.getTarget() or whatever
Object result = null;
if(!activity.isFinishing()) {
result = joinPoint.proceed();
} else {
result = // do something else
}
return result;
}
}
I'd like to know how to determine the calling Activity from within the Aspect.
Okay so it depends on where the method with your annotation is.
If the annotated method is declared within an Activity implementation, then you can indeed call joinpoint.getTarget()and cast the result.
Also you might want to update your pointcut to make sure that the method indeed is on an activity :
execution(#nz.co.vodafone.android.myaccount.aspect.ActivityMustBeShowing * *(..)) && within(android.app.Activity+)
If that's not the case then you might need to add an advice before any activity's onResume() to remember what the current activity is.

Does addJavascriptInterface() rely upon getClass()?

I have tried to trace through the code to see how addJavascriptInterface() on WebView is implemented, but it dives into native code, which basically cripples my ability to grok what is going on.
Specifically, I am trying to determine if the JNI(?) means by which addJavascriptInterface() arranges to call back into Java code relies upon getClass() as part of a reflection strategy, to map method references in JavaScript source to the implementations in Java. I would assume that it has to, and maybe I am searching in the wrong place, but I am not seeing it.
Can anyone point me to the code where the injected Java objects are used, so we can see how that is implemented?
Thanks!
UPDATE
To clarify, I mean using getClass() on the object passed to addJavascriptInterface().
The code that I think you're after is found in external/webkit/Source/WebCore/bridge/jni/. There are two main subdirectories there, jsc and v8 representing the two Javascript engines Android has used. Since V8 is the engine that's been used most recently and for some time, we'll stick with that.
I'm assuming you were able to successfully trace the Java side of the code to get from WebView.addJavascriptInterface() down to BrowserFrame.nativeAddJavaScriptInterface(), I'll leave those details out. The native side is picked up by AddJavaScriptInterface() in external/webkit/Source/WebKit/android/jni/WebCoreFrameBridge.cpp, where the Java object passed in by the application is finally bound to the WebKit frame with bindToWindowObject().
I am trying to determine if the JNI means by which addJavascriptInterface() arranges to call back into Java code relies upon getClass() as part of a reflection strategy
The short answer is yes. They use a lot of wrappers around traditional JNI code, but if you look inside them the accessors on the JNIEnv for doing reflection are present. The wrappers they've created in V8 are:
external/webkit/Source/WebCore/bridge/jni/v8/JavaInstanceJobjectV8.cpp
external/webkit/Source/WebCore/bridge/jni/v8/JavaClassJobjectV8.cpp
external/webkit/Source/WebCore/bridge/jni/v8/JavaMethodJobjectV8.cpp
Going back to WebCoreFrameBridge.cpp, before that object the application passed in is bound, the jobject originally handed into the native code via JNI is wrapped in a JavaInstance class, and then converted to an NPObject, which is the final object bound to WebKit. The source for the V8 NPObject is at:
external/webkit/Source/WebCore/bridge/jni/v8/JavaNPObjectV8.cpp
We can see in the NPObject implementation that the calls always extract the JavaInstance back out and call methods there. If you look at examples like JavaNPObjectHasMethod() or JavaNPObjectInvoke, you'll notice the following line appear frequently:
instance->getClass()->methodsNamed(name)
This returns the JavaClass wrapper they've created, but if you look into the JavaClassJobjectV8 constructor and associated methods you'll see those familiar reflection calls to the Java object using the JNIEnv (including the actual JNI getClass() call into Dalvik).
So when a method is called by the bound WebKit frame, it finds the associated NPObject, which extracts its JavaInstance wrapper, which in turn uses JNI reflection to get access to the Java methods. The chain of custody here is a little harder to follow, so let me know if what's already provided is sufficient to answer your questions.
Here is what I got:
WebView wv = ...;
wv.addJavascriptInterface(object, name);
this goes to:
public void addJavascriptInterface(Object object, String name) {
checkThread();
mProvider.addJavascriptInterface(object, name);
}
mProvider is an interface of type WebViewProvider as it is declared in in WebView class:
//-------------------------------------------------------------------------
// Private internal stuff
//-------------------------------------------------------------------------
private WebViewProvider mProvider;
The only method I can see that instantiates it is ensureProviderCreated():
private void ensureProviderCreated() {
checkThread();
if (mProvider == null) {
// As this can get called during the base class constructor chain, pass the minimum
// number of dependencies here; the rest are deferred to init().
mProvider = getFactory().createWebView(this, new PrivateAccess());
}
}
getFactory() is implemented as:
private static synchronized WebViewFactoryProvider getFactory() {
return WebViewFactory.getProvider();
}
getProvider() is implemented as:
static synchronized WebViewFactoryProvider getProvider() {
// For now the main purpose of this function (and the factory abstraction) is to keep
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
sProviderInstance = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY);
if (sProviderInstance == null) {
if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
sProviderInstance = new WebViewClassic.Factory();
}
return sProviderInstance;
}
getFactoryByName() is implemented as:
private static WebViewFactoryProvider getFactoryByName(String providerName) {
try {
if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
Class<?> c = Class.forName(providerName);
if (DEBUG) Log.v(LOGTAG, "instantiating factory");
return (WebViewFactoryProvider) c.newInstance();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (IllegalAccessException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (InstantiationException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
}
return null;
}
and here is where it uses Reflection. If an exception occurs during instantiating the custom class, WebViewClassic.Factory() will be used instead. Here is how it is implemented:
static class Factory implements WebViewFactoryProvider, WebViewFactoryProvider.Statics {
#Override
public String findAddress(String addr) {
return WebViewClassic.findAddress(addr);
}
#Override
public void setPlatformNotificationsEnabled(boolean enable) {
if (enable) {
WebViewClassic.enablePlatformNotifications();
} else {
WebViewClassic.disablePlatformNotifications();
}
}
#Override
public Statics getStatics() { return this; }
#Override
public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) {
return new WebViewClassic(webView, privateAccess);
}
#Override
public GeolocationPermissions getGeolocationPermissions() {
return GeolocationPermissionsClassic.getInstance();
}
#Override
public CookieManager getCookieManager() {
return CookieManagerClassic.getInstance();
}
#Override
public WebIconDatabase getWebIconDatabase() {
return WebIconDatabaseClassic.getInstance();
}
#Override
public WebStorage getWebStorage() {
return WebStorageClassic.getInstance();
}
#Override
public WebViewDatabase getWebViewDatabase(Context context) {
return WebViewDatabaseClassic.getInstance(context);
}
}
Now go back to mProvider = getFactory().createWebView(this, new PrivateAccess()); where getFactory() is either the custom class (by reflection) or WebViewClassic.Factory.
WebViewClassic.Factory#createWebView() returns WebViewClassic which is a sub-type of mProvider's type.
WebViewClassic#addJavascriptInterface is implemented as:
/**
* See {#link WebView#addJavascriptInterface(Object, String)}
*/
#Override
public void addJavascriptInterface(Object object, String name) {
if (object == null) {
return;
}
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
arg.mObject = object;
arg.mInterfaceName = name;
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
}
I think, this is what you are looking for :)
This is more of a comment than an answer, but I can't add a stacktrace in comments. So here it goes:
When setting a breakpoint in an Object that servers as a JavaScript Interface implementation, this is a sample stack-trace I get:
16> WebViewCoreThread#830034675584, prio=5, in group 'main', status: 'RUNNING'
at com.mediaarc.player.books.model.pagesource.service.EPubPageSourceService$JS.JSReady(EPubPageSourceService.java:1752)
at android.webkit.JWebCoreJavaBridge.nativeServiceFuncPtrQueue(JWebCoreJavaBridge.java:-1)
at android.webkit.JWebCoreJavaBridge.nativeServiceFuncPtrQueue(JWebCoreJavaBridge.java:-1)
at android.webkit.JWebCoreJavaBridge.handleMessage(JWebCoreJavaBridge.java:113)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:814)
at java.lang.Thread.run(Thread.java:841)
It starts in Java (Thread.run --> handleMessage). Then it disappears into Native code (nativeServiceFuncPtrQueue) and it comes out again in Java (nativeServiceFuncPtrQueue --> JSReady).
This stack is from a Nexus 10 running 4.3.
There is something going on in the Native Layer that moves the execution from within a call to nativeServiceFuncPtrQueue directly to the Java method of the JavaScriptInterface instance in Java.
Nowadays, the JavaScriptInterface need to annotate each method that it publishes to JavaScript (#JavaScriptInterface method annotation). Maybe this generates some JNI bridges on the fly calling from Native into Java.
I wonder how this stack-trace would have looked like on an older device where the #JavaScriptInterface annotations were not necessary.
from Understanding Android's webview addjavascriptinterface : "The method WebView.addJavascriptInterface sends a message to an instance of WebViewCore:
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg); In WebViewCore.java there are a bunch of overloaded methods called sendMessage , but we don't really need to know which exactly is being called, since they do pretty much the same thing. There's even a nice comment to give us a hint that we're in the right place! All of them are delegating to an instance of EventHub which is some inner class. This method turns out to be synchronized, and is sending a message to an instance of Handler, which is a good indication that this is probably running in another thread, but for completeness sake, let's find out!
That Handler is instantiated in EventHub.transferMessages which is called from WebViewCore.initialize . There are a few more hops here, but eventually I found out that this is called from run in WebCoreThread (subclass of Runnable), which is instantiated along with a new Thread right here ." instantiated along with a new Thread right here ."
synchronized (WebViewCore.class) {
if (sWebCoreHandler == null) {
// Create a global thread and start it.
Thread t = new Thread(new WebCoreThread());
t.setName(THREAD_NAME);
t.start();
try {
WebViewCore.class.wait();
} catch (InterruptedException e) {
Log.e(LOGTAG, "Caught exception while waiting for thread " +
"creation.");
Log.e(LOGTAG, Log.getStackTraceString(e));
}
}
}
In other words, this could be the chain of calls in my opinion:
android.webkit.WebViewClassic
4159 #Override
4160 public void More ...addJavascriptInterface(Object object, String name) {
4161
4162 if (object == null) {
4163 return;
4164 }
4165 WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
4166
4167 arg.mObject = object;
4168 arg.mInterfaceName = name;
4169
4170 // starting with JELLY_BEAN_MR1, annotations are mandatory for enabling access to
4171 // methods that are accessible from JS.
4172 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
4173 arg.mRequireAnnotation = true;
4174 } else {
4175 arg.mRequireAnnotation = false;
4176 }
4177 mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
4178 }
android.webkit.WebViewCore
static class JSInterfaceData {
827 Object mObject;
828 String mInterfaceName;
829 boolean mRequireAnnotation;
830 }
java.lang.Object
37 public class Object {
38
39 private static native void registerNatives();
40 static {
41 registerNatives();
42 }
Returns the runtime class of this Object. The returned Class object is the object that is locked by static synchronized methods of the represented class. The actual result type is Class where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
Returns: The Class object that represents the runtime class of this object. See also: The Java Language Specification, Third Edition (15.8.2 Class Literals)
64
65 public final native Class<?> getClass();
From a Dalvik's perspective I think you are just registering a JNI callback via findClass like this from JNIHelp.c :
/*
* Register native JNI-callable methods.
*
* "className" looks like "java/lang/String".
*/
int jniRegisterNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;
LOGV("Registering %s natives\n", className);
clazz = (*env)->FindClass(env, className);
if (clazz == NULL) {
LOGE("Native registration unable to find class '%s', aborting\n",
className);
abort();
}
if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
LOGE("RegisterNatives failed for '%s', aborting\n", className);
abort();
}
(*env)->DeleteLocalRef(env, clazz);
return 0;
}
In conclusion my idea is derived from Native Libraries:
//Get jclass with env->FindClass
so maybe FindClass could be used instead of getClass...

Categories

Resources