J'ai utilisé javah pour générer une fonction JNI native:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ttm_zpay_zPayTestTool */

#ifndef _Included_com_ttm_zpay_zPayTestTool
#define _Included_com_ttm_zpay_zPayTestTool
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ttm_zpay_zPayTestTool
 * Method:    KiziStartTransaction
 * Signature: ()[B
 */
JNIEXPORT jbyteArray JNICALL Java_com_ttm_zpay_zPayTestTool_KiziStartTransaction
  (JNIEnv * env, jobject)
{
   return env->NewByteArray(10);
}

#ifdef __cplusplus
}
#endif
#endif

Pour la classe Java suivante:

package com.ttm.zpay;

public class zPayTestTool
{
   public native byte[] KiziStartTransaction();
}

J'ai vérifié que la fonction native est correctement compilée dans mon fichier * .so final emballé avec mon APK. Je l'ai fait en utilisant readelf -Ws lib.so (readelf fourni par le NDK):

5: 0015fa15    10 FUNC    GLOBAL DEFAULT    8 Java_com_ttm_zpay_zPayTestTool_KiziStartTransaction

Dans la sortie logcat, j'obtiens ce qui suit:

01-17 01:06:02.306  7017  7017 W dalvikvm: No implementation found for native Lcom/ttm/zpay/zPayTestTool;.KiziStartTransaction:()[B
01-17 01:06:02.306  7017  7017 D AndroidRuntime: Shutting down VM
01-17 01:06:02.311  7017  7017 W dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x40ccd930)
01-17 01:06:02.316  3556  3758 D AudioHardware: openPcmOut_l() mPcmOpenCnt: 0
01-17 01:06:02.321  7017  7017 E AndroidRuntime: FATAL EXCEPTION: main
01-17 01:06:02.321  7017  7017 E AndroidRuntime: java.lang.UnsatisfiedLinkError: Native method not found: com.ttm.zpay.zPayTestTool.KiziStartTransaction:()[B
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.ttm.zpay.zPayTestTool.KiziStartTransaction(Native Method)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.ttm.zpay.zPayActivity.OnKiziStartTransaction(zPayActivity.java:97)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.ttm.zpay.zPayActivity.access$1(zPayActivity.java:95)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.ttm.zpay.zPayActivity$1.onClick(zPayActivity.java:90)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.view.View.performClick(View.java:4204)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.view.View$PerformClick.run(View.java:17355)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.os.Handler.handleCallback(Handler.java:725)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:92)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.os.Looper.loop(Looper.java:137)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:5041)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at java.lang.reflect.Method.invokeNative(Native Method)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at java.lang.reflect.Method.invoke(Method.java:511)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-17 01:06:02.321  7017  7017 E AndroidRuntime:        at dalvik.system.NativeStart.main(Native Method)
01-17 01:06:02.331  3837  3848 W ActivityManager:   Force finishing activity com.ttm.zpay/.zPayActivity

Ce qui est encore plus étrange, c'est que j'ai déjà une autre méthode native dans cette bibliothèque utilisant la même convention de dénomination mais pour une classe Java différente qui fonctionne parfaitement. C'est seulement celui ci-dessus qui pose des problèmes.

Voir le code de la fonction JNI fonctionnelle ci-dessous.

Java:

package com.ttm.zpay;
public class zPayService extends Service
{
   public native boolean Initialize();
}

C ++:

extern "C"
{
    JNIEXPORT bool JNICALL Java_com_ttm_zpay_zPayService_Initialize(JNIEnv* env, jobject obj)
    {
        // Do stuff
    }
}

Donc à la fin de la journée: les méthodes natives mappées pour ma zPayTestTool classe java ne fonctionnent pas , mais la méthode native mappée sur la classe java zPayService fonctionne très bien.

Qu'est-ce que je fais mal? Est-ce un problème avec mon AndroidManifest.xml? Je suis à court d'idées à ce stade et les résultats sur Google et d'autres questions apparemment en double sur SO n'aident pas.

1
void.pointer 17 janv. 2017 à 04:21

2 réponses

Meilleure réponse

J'ai compris quel était le problème. Dans mon AndroidManifest.xml, l'attribut process était défini sur mon élément <service> mais pas sur <application>:

<application
    android:name="com.ttm.zpay.zPayApplication"
    android:allowBackup="true"
    android:label="@string/app_name" 
    android:persistent="true" >

    <service
        android:name="com.ttm.zpay.zPayService"
        android:exported="true"
        android:process="com.ttm.zPayService" >
    </service>

    <activity
        android:name="com.ttm.zpay.zPayActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
</application>

Pour une raison quelconque, cela empêche les méthodes JNI définies dans la ou les classes d'activité qu'elle utilise. J'ai déplacé l'attribut process vers <application> et il semble fonctionner maintenant:

<application
    android:name="com.ttm.zpay.zPayApplication"
    android:allowBackup="true"
    android:label="@string/app_name" 
    android:persistent="true"
    android:process="com.ttm.zPayService">

    <service
        android:name="com.ttm.zpay.zPayService"
        android:exported="true">
    </service>

    <activity
        android:name="com.ttm.zpay.zPayActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
</application>
1
void.pointer 17 janv. 2017 à 14:53

Vous devez l'ajouter dans votre build.gradle

externalNativeBuild {
        ndkBuild {
            path '<path to you android.mk file>'
        }
}

OU

Vous pouvez faire un clic droit sur le dossier de l'application dans le volet projet qui se trouve sur le côté droit d'Android Studio aller à l'option liez le code c / c ++ à votre projet

1
Sachin Verma 17 janv. 2017 à 10:48