我不确定是否有人可以提供帮助,但这确实很奇怪。我构建了一个android应用程序,并在本地对其进行了测试,一切正常。然后,我将其发布到应用程序商店,并且一直崩溃。
谷歌播放的堆栈跟踪显示:
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
。但是请注意,在开发应用程序并在不同设备上进行测试时,不会发生此错误。只有在将其上传到Google Play并从那里下载后,此错误才会出现。
所以我看了看我的SignedRequestHelper类,当时的样子是这样的:
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()
方法更改为如下所示。只需删除最后两个替换标签:
private String percentEncodeRfc3986(String s) {
String out;
try {
out = URLEncoder.encode(s, UTF8_CHARSET)
.replace("+", "%20");
} catch (UnsupportedEncodingException e) {
out = s;
}
return out;
}
然后在本地对其进行测试:它可以工作。然后将其发布到Google Play并下载:它有效。
因此,一切都很好,但是我留在这里想知道为什么现在这确实起作用了。
这也让我感到紧张,因为当应用程序上传到Google Play时,突然之间在我的模拟器和测试设备上完美运行的代码无法正常工作。这似乎是一件微不足道的事情...一些额外的替换导致此错误。
有人可以帮我了解这里发生了什么吗?或者至少至少为什么有时发布在Google Play上的应用程序上的代码可能无法像在本地dev中那样完全无法工作或执行?
编辑:我的build.gradle文件:
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'
}
}
}
经过一些测试后,我确定出现此错误的原因是因为我最初发布App时没有更新SDK和Android Studio中的其他更新。因为在更新后,我将代码恢复为崩溃时的样子,并且一切正常-这是有道理的,因为我真的没有理由不认为我的代码无法正常工作。
因此,在这里的课程是,在签署应用的发布版本之前,请确保所有SDK工具和Android Studio都是最新的!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句