本文介绍了从Google Play下载Android应用时崩溃,但在本地开发中效果很好 - 为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定是否有人可以帮忙,但这真的很奇怪。我构建了一个Android应用程序,并在本地进行了测试,并且一切正常然后,我将它发布到应用商店,并且一直在崩溃。

I'm not sure if anyone can help with this but it is something really strange. I built an android app and tested it locally and everything works great. Then, I published it to the app store and it kept crashing.

google play上的堆栈跟踪显示:

The stack trace on google play showed:

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:300)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.length()' on a null object reference
    at libcore.net.UriCodec.encode(UriCodec.java:132)
    at java.net.URLEncoder.encode(URLEncoder.java:57)
    at com.xxxx.yyyy.bbbb.SignedRequestsHelper.percentEncodeRfc3986(SignedRequestsHelper.java:120)
    at com.xxxx.yyyy.bbbb.SignedRequestsHelper.sign(SignedRequestsHelper.java:63)
    at com.xxxx.yyyy.SearchFragment$SearchAsyncTask.doInBackground(SearchFragment.java:385)
    at com.xxxx.yyyy.SearchFragment$SearchAsyncTask.doInBackground(SearchFragment.java:338)
    at android.os.AsyncTask$2.call(AsyncTask.java:288)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    ... 4 more

所以看起来像是我的 SignedRequestsHelper.percentEncodeRfc3986 )方法。一个字符串是 null 。请注意,在开发应用程序并在不同设备上测试它时,此错误不会发生。它只是在上传到谷歌播放并从那里下载它出现这个错误。

So it looks like there is something going on with my SignedRequestsHelper.percentEncodeRfc3986() method. A string is null. Note though, that this error did NOT happen when developing the app and testing it on different devices. It was only after uploading it to google play and downloading it from there that this error appeared.

因此,我查看了当时的SignedRequestHelper类,它看起来像这样:

So I looked in my SignedRequestHelper class which at the time looked like this:

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TimeZone;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class SignedRequestsHelper {
    private static final String UTF8_CHARSET = "UTF-8";
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    private static final String REQUEST_URI = "/onca/xml";
    private static final String REQUEST_METHOD = "GET";

    // use xml-uk.amznxslt.com for xslt requests, or ecs.amazonaws.co.uk for others
    private String endpoint = "webservices.amazon.com"; // must be lowercase

    // change this so reads from properties file
    private String awsAccessKeyId = "xxxx";
    private String awsSecretKey = "xxx";

    private SecretKeySpec secretKeySpec = null;
    private Mac mac = null;

    public SignedRequestsHelper() throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        byte[] secretyKeyBytes = awsSecretKey.getBytes(UTF8_CHARSET);
        secretKeySpec =
                new SecretKeySpec(secretyKeyBytes, HMAC_SHA256_ALGORITHM);
        mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
        mac.init(secretKeySpec);
    }

    public String sign(Map<String, String> params) {
        params.put("AWSAccessKeyId", awsAccessKeyId);
        params.put("Timestamp", timestamp());

        SortedMap<String, String> sortedParamMap =
                new TreeMap<String, String>(params);
        String canonicalQS = canonicalize(sortedParamMap);
        String toSign =
                REQUEST_METHOD + "\n"
                        + endpoint + "\n"
                        + REQUEST_URI + "\n"
                        + canonicalQS;

        String hmac = hmac(toSign);
        String sig = percentEncodeRfc3986(hmac);
        String url = "http://" + endpoint + REQUEST_URI + "?" +
                canonicalQS + "&Signature=" + sig;

        return url;
    }

    private String hmac(String stringToSign) {
        String signature = null;
        byte[] data;
        byte[] rawHmac;
        try {
            data = stringToSign.getBytes(UTF8_CHARSET);
            rawHmac = mac.doFinal(data);
            Base64 encoder = new Base64();
            signature = new String(encoder.encode(rawHmac));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(UTF8_CHARSET + " is unsupported!", e);
        }
        return signature;
    }

    private String timestamp() {
        String timestamp = null;
        Calendar cal = Calendar.getInstance();
        DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        dfm.setTimeZone(TimeZone.getTimeZone("GMT"));
        timestamp = dfm.format(cal.getTime());
        return timestamp;
    }

    private String canonicalize(SortedMap<String, String> sortedParamMap)
    {
        if (sortedParamMap.isEmpty()) {
            return "";
        }

        StringBuffer buffer = new StringBuffer();
        Iterator<Map.Entry<String, String>> iter =
                sortedParamMap.entrySet().iterator();

        while (iter.hasNext()) {
            Map.Entry<String, String> kvpair = iter.next();
            buffer.append(percentEncodeRfc3986(kvpair.getKey()));
            buffer.append("=");
            buffer.append(percentEncodeRfc3986(kvpair.getValue()));
            if (iter.hasNext()) {
                buffer.append("&");
            }
        }
        String cannoical = buffer.toString();
        return cannoical;
    }

    private String percentEncodeRfc3986(String s) {
        String out;
        try {
            out = URLEncoder.encode(s, UTF8_CHARSET)
                    .replace("+", "%20")
                    .replace("*", "%2A")
                    .replace("%7E", "~");
        } catch (UnsupportedEncodingException e) {
            out = s;
        }
        return out;
    }
}

我更改了 percentEncodeRfc3986 ()方法看起来像这样。删除最后两个替换标签:

And I changed the percentEncodeRfc3986() method to look like this. Just removing the last two replace tags:

private String percentEncodeRfc3986(String s) {
        String out;
        try {
            out = URLEncoder.encode(s, UTF8_CHARSET)
                    .replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            out = s;
        }
        return out;
    }

然后在本地进行测试:工作正常。然后发布到谷歌播放和下载它:它的工作。

Then tested it locally: It works. And then published it to google play and downloaded it: It works.

所以一切都很好,但我现在还在为此挠头,为什么现在这个工作正在进行

这也让我感到紧张,因为 代码在我的模拟器和测试设备上完美运行,突然在应用上传时失效谷歌播放。这似乎是一件小事......一些额外的替换导致了这个错误。

It also makes me nervous because code that worked perfectly on my emulator and test devices all of the sudden did not work when the app was uploaded to google play. This seems like a trivial matter... some extra replacing causing this error.

有人可以帮我理解这里发生了什么吗?至少为什么有时候发布到谷歌播放的应用程序上的代码可能无法正常工作或执行像本地开发?

Could someone help me understand what is happening here? Or at least why sometimes code on an app published to google play might not work or execute exactly like in local dev?

编辑:
我的build.gradle文件:

My build.gradle file:

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.xxx.yyy"
        minSdkVersion 10
        targetSdkVersion 22
        versionCode 8
        versionName "1.2"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}


推荐答案

在做了一些测试之后,了解错误是因为我最初发布我的应用程序时没有更新我的SDK和Android Studio中的其他更新。因为在我更新之后,我将代码恢复到了崩溃时的方式,并且一切正常 - 这很有道理,因为我真的没有看到我的代码没有理由不工作。

After doing some tests, I determined that the reason I got that error was because I did not update my SDK and other updates in Android Studio when I initially published my App. Because after I updated I reverted my code to the way it was when it was crashing and everything worked fine - which makes sense because I really saw absolutely no reason for my code to not be working.

所以这里的教训是确保所有SDK工具和Android Studio在签署应用程序发行版之前都是最新的!

So yeah lesson here is make sure all of your SDK tools and Android Studio are all up to date before signing the release version of your app!

这篇关于从Google Play下载Android应用时崩溃,但在本地开发中效果很好 - 为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 00:59