8
votes

Impossible de charger une bibliothèque partagée native avec des dépendances dans une application d'activité native

Dans mon application Android, j'ai 4 bibliothèques: xxx pré>

Si j'écris une petite ligne de commande exécutable qui lie contre libtemplate et appeler manuellement anativeactivity_oncreate, il relie et fonctionne simplement (si je point Ld_library_path to /data/data/com.mycompany.template/lib)


IF I Exécutez mon application I Obtenez ce message d'erreur très utile: P>
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mycompany.Template"
        android:versionCode="1"
        android:versionName="1.0">

    <!-- This is the platform API where NativeActivity was introduced. -->
    <uses-sdk android:minSdkVersion="9" />

    <!-- This .apk has no Java code itself, so set hasCode to false. -->
    <application android:label="Template Porkholt project" android:hasCode="false">

        <!-- Our activity is the built-in NativeActivity framework class.
             This will take care of integrating with our NDK code. -->
        <activity android:name="android.app.NativeActivity"
                android:label="Template Porkholt project"
                android:configChanges="orientation|keyboardHidden">
            <!-- Tell NativeActivity the name of or .so -->
            <meta-data android:name="android.app.lib_name"
                    android:value="Template" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest> 
<!-- END_INCLUDE(manifest) -->


2 commentaires

Pourriez-vous me laisser savoir comment vous «appelez manuellement anativeactivity_oncreate»? Avez-vous fait cela en code C?


Comment supprimez-vous les numéros de version de l'enseignement? Avez-vous dû reconstruire toutes vos dépendances en supprimant les suffixes de la version? (Je me rends compte que c'est vraiment vieux, mais j'essaie de faire la même chose et je m'interrogee à ce sujet).


4 Réponses :


0
votes

Votre activité a probablement un constructeur statique qui appelle System.load ("libtemplate.so"). Il devrait charger les autres bibliothèques en fonction de l'ordre de dépendance.


0 commentaires

5
votes

Je ne pense pas que Android chargera automatiquement les bibliothèques autres que celles spécifiées dans le manifeste, vous devez donc créer une classe Java "factice" pour charger des dépendances externes, elle doit contenir:

static {
    System.loadLibrary("openal");
    System.loadLibrary("lua");
    System.loadLibrary("png15");
    System.loadLibrary("Porkholt");
    System.loadLibrary("Template");
}


1 commentaires

Oui, c'était le problème, mais j'ai réussi à résoudre sans Java. Je vais poster ma solution



12
votes

Depuis apparemment Android n'est pas suffisamment intelligent pour définir correctement un LD_Library_Path, j'ai réussi à résoudre mon problème en créant une petite bibliothèque de bootstrapper qui charge manuellement l'activité réelle. Voici le code:

#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Porkholt", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "Porkholt", __VA_ARGS__))

#define LIB_PATH "/data/data/@PH_BUNDLE_ID@/lib/"

void * load_lib(const char * l)
{
    void * handle = dlopen(l, RTLD_NOW | RTLD_GLOBAL);
    if (!handle)
    {
        LOGE("dlopen(\"%s\"): %s", l, strerror(errno));
        exit(1);
    }
    return handle;
}

void ANativeActivity_onCreate(ANativeActivity * app, void * ud, size_t udsize)
{
    LOGI("Loaded bootstrap");
    load_lib(LIB_PATH "libpng15.so");
    load_lib(LIB_PATH "liblua.so");
    load_lib(LIB_PATH "libopenal.so");
    load_lib(LIB_PATH "libPorkholt.so");
    void (*main)(ANativeActivity*, void*, size_t) = dlsym(load_lib(LIB_PATH "lib@PH_APP_TARGET@.so"), "ANativeActivity_onCreate");
    if (!main)
    {
        LOGE("undefined symbol ANativeActivity_onCreate");
        exit(1);
    }
    main(app, ud, udsize);
}


2 commentaires

Merci da_petcu21. Chargement de bibliothèques dans la JVM avec code natif C'est une contribution précieuse;) ... +1


Dis-vous que le seul moyen de faire une activité d'activité native. Les bibliothèques sont de faire une deuxième activité native charger manuellement les bibliothèques et lancent la première activité native? Sinon, pourriez-vous élaborer comment votre solution fonctionne? Travaillé sur cette question depuis un certain temps maintenant sans très peu de chance.



1
votes

Ceci n'affecte plus l'API 24+ (voir le Frameworc correction ici ). Toutefois, si vous devez prendre en charge les anciennes versions, étendre NativeActivity , reportez-vous à votre extension dans le fichier manifeste et ajoutez le bloc statique mentionné dans La réponse de la SDRA comme solution de contournement.


0 commentaires