我更新了一个应用程序,但它失败了。 ProGuard 中缺少类型参数

Posted

技术标签:

【中文标题】我更新了一个应用程序,但它失败了。 ProGuard 中缺少类型参数【英文标题】:I updated an App but its failed. Missing type parameter in ProGuard 【发布时间】:2015-10-11 11:04:22 【问题描述】:

我更新了一个代码几乎相同的应用程序,在以前的版本中我在 proguard 中没有问题。当我从 androidStudio 启动应用程序时我没有问题,但是当我在应用程序的某些部分启动已签名的应用程序时会显示此错误:

07-21 14:45:02.156  24372-24372/pe.gob.devida E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Missing type parameter.
            at com.google.a.c.a.a(Unknown Source)
            at com.google.a.c.a.<init>(Unknown Source)
            at pe.gob.devida.fragments.c.<init>(Unknown Source)
            at pe.gob.devida.fragments.b.a(Unknown Source)
            at pe.gob.devida.fragments.b.a(Unknown Source)
            at com.a.a.a.o.c(Unknown Source)
            at com.a.a.a.o.b(Unknown Source)
            at com.a.a.i.run(Unknown Source)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)
07-21 14:45:02.584  24372-32210/pe.gob.devida E/Google Maps Android API﹕ Authorization failure.  Please see https://developers.google.com/maps/documentation/android/start for how to correctly set up the map.
07-21 14:45:02.588  24372-32210/pe.gob.devida E/Google Maps Android API﹕ In the Google Developer Console (https://console.developers.google.com)
    Ensure that the "Google Maps Android API v2" is enabled.
    Ensure that the following Android Key exists:
    API Key: YOUR_KEY_HERE
    Android Application (<cert_fingerprint>;<package_name>): 9A:69:09:32:33:57:C3:8B:42:35:E7:82:07:6C:F9:DF:82:A0:AD:2B;pe.gob.devida

APIKey 存在且“Google Maps Android API v2”已启用

我认为问题出在 proguard-rules.pro

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\Diego\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose

-dontwarn pe.gob.devida.**
-dontwarn org.simpleframework.**
-dontwarn com.squareup.picasso.**
-dontwarn com.parse.**
-dontwarn com.google.gsom.**

-keep public class * extends pe.gob.devida.activities.BaseActivity
-keep public class * extends pe.gob.devida.fragments.BaseFragment
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the javascript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview 
#   public *;
#

使用Gson时BaseActivity和BaseFragment扩展类出现错误。

BaseActivity.class

package pe.gob.devida.activities;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.toolbox.StringRequest;

import pe.gob.devida.volley.VolleySingleton;

import java.util.Map;

/**
 * Created by Diego on 14/06/2015.
 */
public abstract class BaseActivity extends AppCompatActivity 
    private VolleySingleton singleton;
    protected RequestQueue fRequestQueue;
    private static final int TIME_OUT = 10000, NUM_RETRY = 3;
    private ProgressBar progressBar;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        singleton = VolleySingleton.getInstance(this.getApplicationContext());
        fRequestQueue = singleton.getRequestQueue();
        progressBar = new ProgressBar(this);
    

    public void addToQueue(Request request) 
        onPreStartConnection();
        if (request != null) 
            request.setTag(this);
            if (fRequestQueue == null)
                fRequestQueue = singleton.getRequestQueue();
            request.setRetryPolicy(new DefaultRetryPolicy(TIME_OUT, NUM_RETRY,
                    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
            fRequestQueue.add(request);
        
    

    public void onPreStartConnection() 
        setProgressBarIndeterminateVisibility(true);
    

    public void onConnectionFinished() 
        setProgressBarIndeterminateVisibility(false);
    

    public void onConnectionFailed(String error) 
        setProgressBarIndeterminateVisibility(false);
        Toast.makeText(this, error, Toast.LENGTH_LONG).show();
    


    public void makeStringRequest(int method, String url, Response.Listener<String> listener,
                                  Response.ErrorListener errorListener, final Map headers,
                                  final Map params) 
        StringRequest request = new StringRequest(method, url, listener, errorListener) 
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError 
                return headers;
            

            @Override
            protected Map<String, String> getParams() throws AuthFailureError 
                return params;
            
        ;
        addToQueue(request);
    

    public void makeStringRequest(int method, String url, Response.Listener<String> listener,
                                  Response.ErrorListener errorListener) 
        StringRequest request = new StringRequest(method, url, listener, errorListener);
        addToQueue(request);
    

    protected abstract Response.Listener getListener();
    protected abstract Response.ErrorListener getErrorListener();


BaseFragment.class

public abstract class BaseFragment extends Fragment 

    private VolleySingleton singleton;
    protected RequestQueue fRequestQueue;
    private static final int TIME_OUT = 10000, NUM_RETRY = 3;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        singleton = VolleySingleton.getInstance(getActivity().getApplicationContext());
        fRequestQueue = singleton.getRequestQueue();
    

    public void addToQueue(Request request) 
        if (request != null) 
            request.setTag(this);
            if (fRequestQueue == null)
                fRequestQueue = singleton.getRequestQueue();
            request.setRetryPolicy(new DefaultRetryPolicy(TIME_OUT, NUM_RETRY,
                    DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
            onPreStartConnection();
            fRequestQueue.add(request);
        
    

    public void onPreStartConnection() 
        getActivity().setProgressBarIndeterminateVisibility(true);
    

    public void onConnectionFinished() 
        getActivity().setProgressBarIndeterminateVisibility(false);
    

    public void onConnectionFailed(String error) 
        getActivity().setProgressBarIndeterminateVisibility(false);
        Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show();
    

    public void makeStringRequest(int method, String url, Response.Listener<String> listener,
                                  Response.ErrorListener errorListener, final Map headers,
                                  final Map params) 
        onPreStartConnection();
        StringRequest request = new StringRequest(method, url, listener, errorListener) 
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError 
                return headers;
            

            @Override
            protected Map<String, String> getParams() throws AuthFailureError 
                return params;
            
        ;
    

    public void makeStringRequest(int method, String url, Response.Listener<String> listener,
                                  Response.ErrorListener errorListener) 
        onPreStartConnection();
        StringRequest request = new StringRequest(method, url, listener, errorListener);
        addToQueue(request);
    

    public void makeStringRequest(int method, String url) 
        onPreStartConnection();
        StringRequest request = new StringRequest(method, url, getListener(), getErrorListener());
        addToQueue(request);
    

    protected abstract Response.Listener getListener();

    protected abstract Response.ErrorListener getErrorListener();

当我打开这个片段时会显示日志: CentrosFragment.class

public class CentrosFragment extends BaseFragment implements OnMapReadyCallback 

    SupportMapFragment mapFragment;
    GoogleMap gMap;
    private List<MarkerOptions> list = Collections.emptyList();
    private List<Establecimiento> data = Collections.emptyList();
    private final static String URL ="http://www.eljade.com.pe/app/obtener_establecimientos.php";

    public CentrosFragment() 
        // Required empty public constructor
    

    @Override
    public void onResume() 
        super.onResume();
        if (android.os.Build.VERSION.SDK_INT > 12) 
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
                    .permitAll().build();
            StrictMode.setThreadPolicy(policy);
        
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        View root = inflater.inflate(R.layout.fragment_centros, container, false);
        mapFragment = (SupportMapFragment) this.getChildFragmentManager()
                .findFragmentById(R.id.centrosMap);
        mapFragment.getMapAsync(this);
        return root;
    


    @Override
    public void onMapReady(GoogleMap googleMap) 
        gMap = googleMap;
        gMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        gMap.getUiSettings().setZoomControlsEnabled(true);
        gMap.setMyLocationEnabled(true);
        LatLng myPosition = new LatLng(-12.046374,
                -77.0427934);
        gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myPosition, Constant.FIRST_ZOOM));
        makeStringRequest(Request.Method.GET, URL);
        /*getData();
        for (int i = 0; i < list.size(); i++) 
            gMap.addMarker(list.get(i));
        */
    
    @Override
    protected Response.Listener getListener() 
        return new Response.Listener<String>() 
            @Override
            public void onResponse(String response) 
                Type listType = new TypeToken<List<Establecimiento>>() .getType();
                data = new Gson().fromJson(response, listType);
                for (int i = 0; i<data.size(); i++)
                    gMap.addMarker(data.get(i).getMarker());
                
            
        ;
    

    @Override
    protected Response.ErrorListener getErrorListener() 
        return new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 

            
        ;
    

【问题讨论】:

类型 listType = new TypeToken>() .getType();你应该在这里检查。这里可能有问题。或者如果任何线程试图到达创建的对象,这也可能导致错误。 正如我所说,自 AndroidStudio 以来,当我启动时,他的 apk 运行良好。我认为错误在 proguard-rules.pro 中。 【参考方案1】:

我用这个解决了我的问题:

保护:

-renamesourcefileattribute SourceFile
-keepattributes  Signature,SourceFile,LineNumberTable
-keep public class * extends android.app.Application

【讨论】:

【参考方案2】:

你可以试试这个

-keep class * implements java.io.Serializable 
     static final long serialVersionUID;
     private static final java.io.ObjectStreamField[] serialPersistentFields;
     private void writeObject(java.io.ObjectOutputStream);
     private void readObject(java.io.ObjectInputStream);
     java.lang.Object writeReplace();
     java.lang.Object readResolve();
     private *;
     void set*(***);
     *** get*();

# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# Gson specific classes
-keep class sun.misc.Unsafe  *; 
#-keep class com.google.gson.stream.**  *; 

# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.**  *; 

【讨论】:

以上是关于我更新了一个应用程序,但它失败了。 ProGuard 中缺少类型参数的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 身份验证在发布模式下失败

Spyder 的 Anaconda 更新失败

Visual Studio设置失败

我运行下面的 rmi 程序,但它显示命令执行失败

如何使用 querydsl 测试更新?

更新到 Kotlin 1.4 后,Android Gradle 构建失败 dexBuilderDebug 任务