Errores de "referencia indefinida a" durante el enlace de la biblioteca nativa por el complemento gradle "experimental"
Traté de crear una aplicación JNI simple con un nuevo sistema de compilación basado en com.android "experimental".modelo.application (com.android.tools.build:gradle-experimental:0.9.2).
./gradle/wrapper/gradle-wrapper.properties:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
./build.gradle:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.9.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
./app/build.gradle:
apply plugin: 'com.android.model.application'
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def project_src_main = project.getRootDir().absolutePath + '/app/src/main'
model {
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
ndk {
moduleName = 'android-cpp-sandbox'
toolchainVersion "4.9"
platformVersion 16
stl 'gnustl_static'
abiFilters.addAll(['armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'])
}
defaultConfig {
applicationId 'com.lamersoft.androidcppsandbox'
minSdkVersion.apiLevel 23
targetSdkVersion.apiLevel 25
}
sources {
main {
manifest {
source.srcDir project_src_main
}
java {
source.srcDir project_src_main + '/java'
}
res {
source.srcDir project_src_main + '/res'
}
jni {
source.srcDir project_src_main + '/jni'
}
}
}
productFlavors {
create("arm7") {
ndk.abiFilters.add('armeabi-v7a')
}
create("arm8") {
ndk.abiFilters.add('arm64-v8a')
}
create("x86") {
ndk.abiFilters.add('x86')
}
create("x86-64") {
ndk.abiFilters.add('x86_64')
}
create("all") {
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:design:25.3.1'
}
./app/src/main/res/layout/activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lamersoft.androidcppsandbox.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_main"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
./app/src/main/res/layout/content_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main"
tools:context="com.lamersoft.androidcppsandbox.MainActivity">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
./app/src/main/java/com/lamersoft/androidcppsandbox/MainActivity.java:
package com.lamersoft.androidcppsandbox;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, stringFromJNI(), Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});
}
private native String stringFromJNI();
static {
System.loadLibrary("android-cpp-sandbox");
}
}
./app/src/main/jni/main.cpp:
#include <jni.h>
#include <string>
int counter = 1;
extern "C"
JNIEXPORT jstring JNICALL
Java_com_lamersoft_androidcppsandbox_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
char s[100];
snprintf(s, sizeof(s), "Hello from C++ #%d", counter++);
return env->NewStringUTF(s);
}
ModificacionesPara reproducir el problema, crearé una clase C ++ en una carpeta separada y la incluiré en el proyecto agregando la ruta con un cppFlag "-I".
./app/src/main/externalCPP/SampleClass.h:
#ifndef ANDROIDCPPSANDBOX_SAMPLECLASS_H
#define ANDROIDCPPSANDBOX_SAMPLECLASS_H
class SampleClass {
public:
SampleClass(int start);
int count();
private:
int counter = 0;
};
#endif //ANDROIDCPPSANDBOX_SAMPLECLASS_H
./app/src/main/externalCPP/SampleClass.cpp:
#include "SampleClass.h"
SampleClass::SampleClass(int start) {
counter = start;
}
int SampleClass::count() {
return counter++;
}
./app/src/main/jni/main.cpp:
#include <jni.h>
#include <string>
#include <SampleClass.h>
SampleClass *counter = new SampleClass(1);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_lamersoft_androidcppsandbox_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
char s[100];
snprintf(s, sizeof(s), "Hello from C++ #%d", counter->count());
return env->NewStringUTF(s);
}
./app/build.gradle:solo una línea agregada:
...
model {
android {
...
ndk {
...
cppFlags.add('-I' + project_src_main + '/externalCPP')
...
Como puede ver, el proyecto no se compila. Falla conerror: referencia indefinida a 'SampleClass :: count ()' yerror: referencia indefinida a 'SampleClass :: SampleClass (int)'.
Lo mismo sucede cuando trato de usar un terceropreconstruido biblioteca estática en el proyecto definiéndola de esta manera:
...
model {
repositories {
libs(PrebuiltLibraries) {
ThirdPartyLibrary {
headers.srcDir project_src_main + '/externalCPP'
binaries.withType(StaticLibraryBinary) {
staticLibraryFile = file(project_src_main + '/externalCPP/lib/libSomeThirdPartyLibrary' + targetPlatform.getName() + '.a')
}
}
}
}
android {
...
sources {
main {
...
jni {
source.srcDir project_src_main + '/jni'
dependencies {
library 'ThirdPartyLibrary' linkage 'static'
}
}
}
}
...
¿Alguien cómo resolver esto con elexperimental plugin de gradle?