java.lang.NoClassDefFoundError:com.acme.R $ layout引用android库

kld*_*is4 6 android gradle android-studio

我有一个带有自定义身份验证器的Android库项目和一个为验证者提供登录屏幕的Activity.验证器直接包含在我的主应用程序中工作正常,但我想将验证器放入一个单独的Android库.当我运行引用此库的主要Android应用程序项目时,我在Activity的onCreate方法中使用R.layout调用setContentView时得到'java.lang.NoClassDefFoundError:com.acme.R $ layout'.

我正在使用android gradle构建.我已将这些库发布到本地maven存储库,主项目似乎正在构建而没有任何问题.我已经在build/outputs/apk的debug apk中反编译了class.dex文件,我可以看到库中的R $ layout.class文件存在,所以我完全不知道可能是什么问题.

以下是实现自定义身份验证器的服务:

public class AcmeAuthenticatorService extends Service {

public static final String ACME_ACCOUNT_TYPE = "acme-oauth";
public static final String ACME_ACCESS_TOKEN_TYPE = "acme-oauth-access-token";


private static Authenticator authenticator;

private Authenticator getAuthenticator() {
    if (authenticator == null)
        authenticator = new Authenticator(this);
    return authenticator;
}

@Override
public IBinder onBind(Intent intent) {
    if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT))
        return getAuthenticator().getIBinder();
    return null;
}

private static class Authenticator extends AbstractAccountAuthenticator {
    private final Context context;

    Authenticator(Context ctx) {
        super(ctx);
        this.context = ctx;
    }

    @Override
    public Bundle addAccount(AccountAuthenticatorResponse response,
                             String accountType,
                             String authTokenType,
                             String[] requiredFeatures,
                             Bundle options) throws NetworkErrorException {
        return makeAuthIntentBundle(response, options);
    }

    private Bundle makeAuthIntentBundle(AccountAuthenticatorResponse response, Bundle options) {
        Bundle reply = new Bundle();
        Intent i = new Intent(context, AcmeAccountAuthenticatorActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        i.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
        if (options != null)
            i.putExtras(options);
        reply.putParcelable(AccountManager.KEY_INTENT, i);
        return reply;
    }

    @Override
    public Bundle getAuthToken(AccountAuthenticatorResponse response,
                               Account account,
                               String authTokenType,
                               Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
        return null;
    }

    @Override
    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
        return null;
    }

    @Override
    public String getAuthTokenLabel(String authTokenType) {
        return null;
    }

    @Override
    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
        return null;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

这是处理登录的Activity:

import com.acme.R;

public class AcmeAccountAuthenticatorActivity extends AccountAuthenticatorActivity {
private AccountManager accountManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //NoClassDefFoundError occurs for this line
    setContentView(R.layout.activity_account_auth);

    accountManager = AccountManager.get(this);

    WebView webview = (WebView)findViewById(R.id.web_view);
    WebSettings webSettings = webview.getSettings();
    webSettings.setJavaScriptEnabled(true);
    if ( webview == null ) {
        Log.e("TAG", "Web view not found!!");
    } else {
        //Do authentication
    }
}
}
Run Code Online (Sandbox Code Playgroud)

以下是登录活动的布局xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.acme.AcmeAccountAuthenticatorActivity"
tools:ignore="MergeRootFrame" >

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="8dp">
    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />
</LinearLayout>
</FrameLayout>
Run Code Online (Sandbox Code Playgroud)

在库的清单的应用程序部分中,我有:

    <activity android:name="com.acme.AcmeAccountAuthenticatorActivity"
        android:label="Login">
    </activity>

    <service android:name="com.acme.AcmeAuthenticatorService"
             android:permission="com.acme.AUTHENTICATE_ACME_ACCOUNTS">
        <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator"/>
        </intent-filter>
        <meta-data android:name="android.accounts.AccountAuthenticator"
            android:resource="@xml/authenticator"/>
    </service>
Run Code Online (Sandbox Code Playgroud)

以及库的build.gradle:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.12.+'
    }
}

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'

version '1.0-SNAPSHOT'
group 'com.acme'

repositories {
    mavenLocal()
    mavenCentral()
}

android {
    compileSdkVersion 19
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "com.acme.test"
        minSdkVersion 16
        targetSdkVersion 19
    }

    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-project.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile 'com.android.support:support-v4:19.0.0'
    compile 'com.android.support:appcompat-v7:19.0.0'
}

def getArtifactFullPath() {
    return "${buildDir}/outputs/aar/${project.name}-${project.version}.aar"
}

android.libraryVariants
publishing {
    publications {
        maven(MavenPublication) {
            artifact getArtifactFullPath()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在android应用程序中,我执行以下操作来触发auth活动:

    final AccountManagerFuture<Bundle> future = accountManager.addAccount(AcmeAuthenticatorService.ACME_ACCOUNT_TYPE, AcmeAuthenticatorService.ACME_ACCESS_TOKEN_TYPE, null, null, this, new AccountManagerCallback<Bundle>() {
        @Override
        public void run(AccountManagerFuture<Bundle> future) {
            try {
                Bundle bnd = future.getResult();
                showMessage("Account was created");
                Log.d("acme", "AddNewAccount Bundle is " + bnd);

            } catch (Exception e) {
                e.printStackTrace();
                showMessage(e.getMessage());
            }
        }
    }, null);
Run Code Online (Sandbox Code Playgroud)

这是android应用程序的build.gradle:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.12.+'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'maven'

repositories {
    mavenLocal()
    mavenCentral()
}

android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'

    defaultConfig {
        applicationId "com.acme.myapp"
        minSdkVersion 16
        targetSdkVersion 19
    }

    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile 'com.acme:acme-auth:1.0-SNAPSHOT'
    compile 'com.android.support:support-v4:19.+'
    compile 'com.android.support:appcompat-v7:19.+'
}
Run Code Online (Sandbox Code Playgroud)

这是logcat:

E/AndroidRuntime(27992): FATAL EXCEPTION: mainE/AndroidRuntime(27992): Process: com.acme.myapp, PID: 27992
E/AndroidRuntime(27992): java.lang.NoClassDefFoundError: com.acme.R$layout
E/AndroidRuntime(27992):        at com.acme.AcmeAccountAuthenticatorActivity.onCreate(AcmeAccountAuthenticatorActivity.java:29)
E/AndroidRuntime(27992):        at android.app.Activity.performCreate(Activity.java:5231)
E/AndroidRuntime(27992):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
E/AndroidRuntime(27992):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
E/AndroidRuntime(27992):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
E/AndroidRuntime(27992):        at android.app.ActivityThread.access$800(ActivityThread.java:135)
E/AndroidRuntime(27992):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
E/AndroidRuntime(27992):        at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(27992):        at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime(27992):        at android.app.ActivityThread.main(ActivityThread.java:5001)
E/AndroidRuntime(27992):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(27992):        at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(27992):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
E/AndroidRuntime(27992):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
E/AndroidRuntime(27992):        at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager(  575):   Force finishing activity com.acme.myapp/com.acme.AcmeAccountAuthenticatorActivity
W/ActivityManager(  575):   Force finishing activity com.acme.myapp/.MainActivity
W/ActivityManager(  575): Activity pause timeout for ActivityRecord{42071a70 u0 com.acme.myapp/com.acme.AcmeAccountAuthenticatorActivity t75 f}
Run Code Online (Sandbox Code Playgroud)

更新

我已经创建了一个示例项目来演示github上的问题.有关构建和重现错误的说明,请参阅自述文件.

Mur*_*mel 2

只要当前 Android-Gradle Plugin(版本 0.12.2)中的Bug没有修复,解决问题的唯一方法就是applicationIdbuild.gradle

一旦这个错误被修复,我将更新这篇文章

更新:当前版本 0.13.3 仍然产生相同的错误