Prafuldev V R Prafuldev V R - 2 months ago 38
Android Question

Unable to launch Activity in Release mode (with proguard-android-optimize configuration)

This activity in my app isn't launching in release mode with proguard-android-optimize configuration. The activity launches with both debug and release configuration. Since the error occurs only in proguard-android-optimize configuration , I am unable to trace the error from logcat as it renamed all the classes.

Here is the Activity. ( check the function 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;
}

}


Here is my build.gradle file.

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'


Here is the logcat

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)

Answer

You need to use the default proguard file to keep Android classes like activities, views etc from being removed by your proguard task.

For that Android provides a method called getDefaultProguardFile('proguard-android.txt') that you should use in all your projects, unless you want to manage those exceptions yourself

You can use multiple files if you use proguardFiles instead of proguardFile

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