从JNI调用Java方法,要求上下文(this)接收帐户名

时间:2016-03-22 13:47:15

标签: android android-ndk java-native-interface accountmanager

基本问题,但需要复杂的代码:

我想主要使用Android NDK获取在Android设备上使用的帐户名称。出于安全考虑,应尽可能在本机代码中完成。在分析Android的源代码中* 1(见下文)中建议的呼叫时,结果发现它无法访问原始数据库文件而只是因为缺少权限而读出帐户名称

因此我的下一个方法是使用* 1的代码(见下文)并将其放入一个单独的java类" Account"在src文件夹中。不幸的是,它需要活动上下文,我不知道如何在本机代码中请求它,因为一切都应该从本机代码完成而不包括主要活动。我认为它可能是JNI调用的第二个参数thiz,但我对此非常不确定。

我当前的原生代码基于* 2,看起来像这样,但它到目前为止还没有工作。您有任何提示或更好的解决方案吗?我可以直接从本机代码调用AccountManager吗?

// based on http://www.rgagnon.com/javadetails/java-0284.html
JNIEXPORT jstring JNICALL Java_com_example_nils_myapplication_MyNDK_getMyString(JNIEnv* env, jobject thiz){

const char *str;

jclass myclass_class =(jclass) env->NewGlobalRef
        (env->FindClass ("com/example/nils/myapplication/Account"));

jmethodID constructorID = env->GetMethodID
        (myclass_class, "", "()V");

jmethodID methodID = env->GetMethodID
        (myclass_class, "getUsername", "(Landroid/content/Context;)Ljava/lang/String;");

jobject myclass_object =  env->NewObject
        (myclass_class, constructorID);

jstring s = (jstring)  env->CallObjectMethod
        (myclass_object, methodID, thiz);
[...]

这里是Java类

public class Account {
    public Account(){

    };

    // based on https://stackoverflow.com/questions/2727029/how-can-i-get-the-google-username-on-android
        public static String getUsername(Context c) {
            AccountManager manager = AccountManager.get(c);
            android.accounts.Account[] accounts = manager.getAccountsByType("com.google");
            LinkedList<String> possibleEmails = new LinkedList<String>();

            for (android.accounts.Account account : accounts) {
                // TODO: Check possibleEmail against an email regex or treat
                // account.name as an email address only for certain account.type values.
                possibleEmails.add(account.name);
            }

            if (!possibleEmails.isEmpty() && possibleEmails.get(0) != null) {
                String email = possibleEmails.get(0);
                String[] parts = email.split("@");

                if (parts.length > 1)
                    return parts[0];
            }
            return null;
        }


    }

回复评论#1:当然,最初必须在某处调用本机代码。出于测试目的,我将该调用放在我的主要活动的onCreate()方法中。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        MyNDK a = new MyNDK();
        Log.i("MyTag", a.getMyString());

回复第二条评论:MyNDK只是一个加载本机库的简单类,同时定义了getMyString()方法。

public class MyNDK {

    static{
        System.loadLibrary("MyLibrary");
    }
    public native String getMyString();
}

* 1 How can I get the google username on Android?

* 2 http://www.rgagnon.com/javadetails/java-0284.html

1 个答案:

答案 0 :(得分:1)

嗯,谢谢你的提示。我解决了所以这是解决方案:

构造函数需要&lt; init&gt;作为名称

jmethodID constructorID = env->GetMethodID
        (myclass_class, "<init>", "()V")

此外,我接受了迈克尔的建议,并将上下文添加为java和相应的C函数中的参数。 thiz2是我们想要的上下文,而thiz就像迈克尔上面提到的MyNDK的实例一样。

public native String getMyString(Context c);


JNIEXPORT jstring JNICALL Java_com_example_nils_myapplication_MyNDK_getMyString
        (JNIEnv * env, jobject thiz, jobject thiz2) {

嗯,还剩下什么?不返回帐户名,但出于测试目的,我使用了固定的返回字符串。这解决了实际的JNI问题并且app运行正常,而java实现中仍然存在接收帐户名称的错误。

反正。充分解决了。谢谢大家。