无法在发布模式下启动 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/proguard-android-optimize.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 配置)的主要内容,如果未能解决你的问题,请参考以下文章
Android进阶知识——Activity的生命周期和启动模式