无法在发布模式下启动 Activity(使用 proguard-android-optimize 配置)

Posted

技术标签:

【中文标题】无法在发布模式下启动 Activity(使用 proguard-android-optimize 配置)【英文标题】:Unable to launch Activity in Release mode (with proguard-android-optimize configuration) 【发布时间】:2016-09-14 10:35:58 【问题描述】:

我的应用程序中的此活动未在使用 proguard-android-optimize 配置的发布模式下启动。该活动在调试和发布配置下都能正常启动。由于错误仅发生在 proguard-android-optimize 配置中,因此我无法从 logcat 跟踪错误,因为它重命名了所有类。

这里是活动。 (检查函数 onCreateOptionsMenu() )

import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import package.name.CardInfo;
import package.name.CardViewAdapter;
import package.name.DataStore;
import package.name.R;

public class SearchActivity extends AppCompatActivity implements SearchView.OnQueryTextListener 
    List<CardInfo> list;
    ArrayList<String> wrds;
    LinearLayoutManager ll;
    CardViewAdapter adapter;
    RecyclerView rv;
    List<CardInfo> all;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_search);
    Toolbar tb = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(tb);
    list = new ArrayList<>();
    rv = (RecyclerView) findViewById(R.id.rv);
    new LoadData().execute();


class LoadData extends AsyncTask<Void, Void, Void> 
    List<CardInfo> a;
    ProgressDialog pd;
    DataStore ds;
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        ds = new DataStore(SearchActivity.this);
        pd = new ProgressDialog(SearchActivity.this);
        pd.setMessage("Loading ..");
        pd.setIndeterminate(true);
        pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pd.setCanceledOnTouchOutside(false);
        pd.show();
        a = new ArrayList<>();
    

    @Override
    protected void onPostExecute(Void aVoid) 
        super.onPostExecute(aVoid);
        pd.dismiss();
        all = a;
    

    @Override
    protected Void doInBackground(Void... params) 
        ds.open();
        a = ds.getData();
        ds.close();
        Thread t = new Thread() 
            @Override
            public void run() 
                super.run();
                try 
                    Thread.sleep(2000);
                catch (InterruptedException e) 
                    e.printStackTrace();
                

            
        ;
        t.start();
        return null;
    


@Override
public boolean onCreateOptionsMenu(Menu menu) 

    // I believe problem is residing somewhere here in this function


    getMenuInflater().inflate(R.menu.search_activity_menu, menu);
    SearchView sv = (SearchView) menu.findItem(R.id.search_x).getActionView();
    ll = new LinearLayoutManager(getBaseContext());
    sv.onActionViewExpanded();
    sv.setOnQueryTextListener(this);
    return super.onCreateOptionsMenu(menu);


@Override
public boolean onOptionsItemSelected(MenuItem item) 
    return super.onOptionsItemSelected(item);


@Override
public boolean onQueryTextSubmit(String query) 
    return false;


@Override
public boolean onQueryTextChange(String newText) 
    if (newText.length() >= 1) 
        filter(newText);
        rv.setLayoutManager(ll);
        adapter = new CardViewAdapter(getSupportFragmentManager(), list);
        rv.setAdapter(adapter);
        adapter.notifyDataSetChanged();
    
    return true;


void filter(String qry) 
    list.clear();
    wrds = getWords(qry);
    for (CardInfo i : all) 
        for (String query : wrds) 
            if (i.getAmount().toLowerCase().contains(query.toLowerCase()) ||
                    i.getAction().toLowerCase().contains(query.toLowerCase()) ||
                    i.getPurpose().toLowerCase().contains(query.toLowerCase()) ||
                    i.getDesc().toLowerCase().contains(query.toLowerCase()) ||
                    i.getYear().toLowerCase().contains(query.toLowerCase()) ||
                    i.getMonth().toLowerCase().contains(query.toLowerCase()) ||
                    i.getStore().toLowerCase().contains(query.toLowerCase()) ||
                    i.getDay().toLowerCase().contains(query.toLowerCase())

                    ) 
                if (!list.contains(i))
                    list.add(i);
            
        
    



static ArrayList<String> getWords(String msg) 
    ArrayList<String> arr = new ArrayList<>();
    Pattern pattern = Pattern.compile("(\\S+)");
    Matcher matcher = pattern.matcher(msg);
    while (matcher.find()) 
        arr.add(matcher.group());
    
    return arr;



这是我的 build.gradle 文件。

apply plugin: 'com.android.application'

android 
    signingConfigs 
        Pzy64Signing 
            keyAlias 'xxxx'
            keyPassword 'xxxxxxxx'
            storeFile file('/home/pz/bin/Android/keyStore/PzyKeystore.jks')
            storePassword 'xxxxxxxx'
        
   
compileSdkVersion 24
buildToolsVersion "24.0.2"

defaultConfig 
    applicationId "package.name"
    minSdkVersion 15
    targetSdkVersion 24
    versionCode 9
    versionName "9.0"

buildTypes 
    Pzt64Release 
        signingConfig signingConfigs.Pzy64Signing
        minifyEnabled true
        pseudoLocalesEnabled true
        proguardFile '/home/pz/bin/Android/android-sdk/tools/proguard/proguard-android-optimize.txt'
        zipAlignEnabled true
    

productFlavors 
    Pzy64Config 
        proguardFile '/home/pz/bin/Android/android-sdk/tools/proguard/proguard-android-optimize.txt'
        signingConfig signingConfigs.Pzy64Signing
        versionCode 9
        versionName '9.0'
        minSdkVersion 15
        applicationId 'package.name'
        targetSdkVersion 24
    

dexOptions 
    incremental true



dependencies 
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:design:24.2.0'
compile 'com.android.support:cardview-v7:24.2.0'
compile 'com.android.support:recyclerview-v7:24.2.0'
compile 'com.android.support:support-v4:24.2.0'
compile 'com.google.firebase:firebase-ads:9.2.1'

apply plugin: 'com.google.gms.google-services'

这里是日志猫

        FATAL EXCEPTION: main
    Process: package.name, PID: 14035
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.SearchView.a()' on a null object reference
    at pzy64.pocketmath.summary.SearchActivity.onCreateOptionsMenu(Unknown Source)
    at android.app.Activity.onCreatePanelMenu(Activity.java:2866)
    at android.support.v4.app.s.onCreatePanelMenu(Unknown Source)
    at android.support.v7.view.n.onCreatePanelMenu(Unknown Source)
    at android.support.v7.a.ai.onCreatePanelMenu(Unknown Source)
    at android.support.v7.view.n.onCreatePanelMenu(Unknown Source)
    at android.support.v7.a.bk.run(Unknown Source)
    at android.os.Handler.handleCallback(Handler.java:815)
    at android.os.Handler.dispatchMessage(Handler.java:104)
    at android.os.Looper.loop(Looper.java:194)
    at android.app.ActivityThread.main(ActivityThread.java:5550)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:955)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:750)

【问题讨论】:

为什么要从 proguardFiles 中删除 getDefaultProguardFile('proguard-android.txt')?您可以使用逗号分隔多个文件。在开头添加这个,然后添加你的 那么我是否需要从 gradle 文件中删除 Pzt64Release 部分并添加 release 而不是 Pzy64Release 和逗号分隔的文件列表。 这不是来自 proguard 的。该错误似乎来自proguard。只需编辑您的 proguardFiles。保留签名 你的意思是 -keepattributes 签名 不...我的意思是proguardFiles getDefaultProguardFile('proguard-android.txt'), '/home/pz/bin/Android/android-sdk/tools/proguard/proguard-android-optimize.txt' 【参考方案1】:

您需要使用默认的 proguard 文件来防止 Android 类(如活动、视图等)被您的 proguard 任务删除。

为此,Android 提供了一个名为 getDefaultProguardFile('proguard-android.txt') 的方法,您应该在所有项目中使用该方法,除非您想自己管理这些异常

如果使用proguardFiles 而不是proguardFile,则可以使用多个文件

proguardFiles getDefaultProguardFile('proguard-android.txt'),'/home/pz/bin‌​/Android/android-sdk‌​/tools/proguard/prog‌​uard-android-optimiz‌​e.txt', 'proguard-rules.pro'

还将这些行添加到 proguard-rules.pro 文件中

-keep class android.support.v7.widget.**  *; 
-keep interface android.support.v7.widget.**  *; 

【讨论】:

还添加了 -keep class android.support.v7.** ; -keep interface android.support.v7.* *; 在 proguard-rules.pro 中 有必要吗? 我不确定默认文件是否保留它。但为了安全起见,最好保留它 :) 您可以在 Internet 上找到其他有更好记录的 proguard.pro 文件,例如这里 https://github.com/krschultz/android-proguard-snippets/tree/master/libraries

以上是关于无法在发布模式下启动 Activity(使用 proguard-android-optimize 配置)的主要内容,如果未能解决你的问题,请参考以下文章

Activity的四种启动模式

启动模式

Android进阶知识——Activity的生命周期和启动模式

Android进阶知识——Activity的生命周期和启动模式

Activity(活动)的启动模式

Activity的四种启动模式