感謝您花時間閱讀本文。我正在處理涉及Android的項目中遇到了一個非常奇怪的「NoSuchMethodError」。我無法弄清楚這一點,因爲它無視我所有的邏輯。NoSuchMethodError對我的Android設備運行時確實存在的方法
package com.project.qrcode
import android.security.KeyStore;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import jim.h.common.android.lib.zxing.config.ZXingLibConfig;
import jim.h.common.android.lib.zxing.integrator.IntentIntegrator;
import jim.h.common.android.lib.zxing.integrator.IntentResult;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ZXingLibConfig zxingLibConfig;
private Handler handler = new Handler();
private TextView txtScanResult;
KeyStore ks = KeyStore.getInstance();
SecretKeyStore secretKeyStore = new SecretKeyStore();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] hashedBytes;
String decoded;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startActivity(new Intent("android.credentials.UNLOCK"));
} else {
startActivity(new Intent("com.android.credentials.UNLOCK"));
}
} catch (ActivityNotFoundException e) {
Log.e(getPackageName(), "No UNLOCK activity: " + e.getMessage(), e);
}
zxingLibConfig = new ZXingLibConfig();
zxingLibConfig.useFrontLight = true;
txtScanResult = (TextView) findViewById(R.id.scan_result);
Button scanButton = (Button) findViewById(R.id.scan_button);
//Set a listener on the scan button
scanButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!checkIfKeyStored()) {
Toast keyerror = Toast.makeText(getBaseContext(), "You need to complete setup first", Toast.LENGTH_SHORT);
keyerror.show();
return;
}
IntentIntegrator.initiateScan(MainActivity.this, zxingLibConfig);
}
});
Log.v(getPackageName(), "Listener set on scan button");
Button setupButton = (Button) findViewById(R.id.setup_button);
// Set a listener on the setup button
setupButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkIfKeyStored()) {
Log.v(getPackageName(), "Key is already stored");
Toast keyerror = Toast.makeText(getBaseContext(), "You have already completed setup", Toast.LENGTH_SHORT);
keyerror.show();
return;
}
Log.v(getPackageName(), "Key not stored, proceeding with setup");
IntentIntegrator.initiateScan(MainActivity.this, zxingLibConfig);
}
});
Log.v(getPackageName(), "Listener set on setup button");
}
protected boolean checkIfKeyStored() {
String[] keyNames = ks.saw("");
if(keyNames.length == 0) {
return false;
}
return true;
}
// IF setup is done i.e. key is stored send to server
// Otherwise store on phone
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.v(getPackageName(), "Scanned QRCode");
if (requestCode == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (scanResult == null) {
Log.v(getPackageName(), "Scanned nothing");
return;
}
//Contents of the QRCode
Log.v(getPackageName(), "Scan complete, getting result");
final String result = scanResult.getContents();
Log.v(getPackageName(), "Scanned the following code "+ result);
//If there is already a secret key stored i.e. setup already done
if (checkIfKeyStored()) {
Log.v(getPackageName(), "Key already stored, encrypting");
try {
MessageDigest digest = MessageDigest.getInstance("SHA1PRNG");
Log.v(getPackageName(), "Got SHA1PRNG instance");
byte[] keyBytes = ks.get("twofactorkey");
byte[] resultBytes = result.getBytes("UTF-8");
Log.v(getPackageName(), "Got Bytes");
outputStream.write(resultBytes);
outputStream.write(keyBytes);
Log.v(getPackageName(), "Wrote Bytes to output stream");
byte[] bytesToEncrypt = outputStream.toByteArray();
Log.v(getPackageName(), "Wrote to Byte array");
hashedBytes = digest.digest(bytesToEncrypt);
decoded = new String(hashedBytes, "UTF-8");
Log.v(getPackageName(), "Coverted bytes to String");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
@Override
public void run() {
txtScanResult.setText(decoded);
Log.v(getPackageName(), "Set TextView");
}
});
}
else //This is the first time scanning a QRCode, i.e. Setup
{
Log.v(getPackageName(), "Key not stored, first time setup");
byte[] resultBytes;
try {
resultBytes = result.getBytes("UTF-8");
Log.v(getPackageName(), "Result byte array: " + resultBytes);
boolean success = ks.put("twofactorkey", resultBytes);
if (!success) {
int errorCode = ks.getLastError();
throw new RuntimeException("Keystore error: " + errorCode);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.v(getPackageName(), "Stored in keystore");
Toast setupComplete = Toast.makeText(getBaseContext(), "You have completed setup", Toast.LENGTH_SHORT);
setupComplete.show();
}
}
}
}
package android.security;
public class KeyStore {
private boolean put(byte[] key, byte[] value) {
execute('i', key, value);
return mError == NO_ERROR;
}
public boolean put(String key, byte[] value) {
Log.v("KEYSTORE", "Attempting put");
return put(getBytes(key), value);
}
}
我得到的錯誤是.. 02-24 15:25:55.689:E/AndroidRuntime(11016):java.lang.NoSuchMethodError:android.security.KeyStore。把它放在onActivityResult()方法中。
如果您需要完整的logcat,我也可以發佈。
您可以看到我在代碼中植入了一些日誌消息。裏面放的那個從不打印出來。
編輯24/02/14: 以上NoMethod異常已經解決了通過移動KeyStore.java進入同一個包MainActivity.java - 謝謝你拉爾斯
但是我現在有一個新的問題。任何時候我嘗試使用ks.state()或ks.put(),我會得到AssertError的迴應:5 - 根據KeyStore.java,這是一個協議錯誤。
最終編輯 我想出了上述問題。原來我使用AOSP的KeyStore版本僅適用於4.2版以下的Android版本。
可能是您的通話將您的字符串的getBytes不能被編碼和「的行爲此字符串不能在給定字符集中編碼時,此方法未指定。「也許針對UnsupportedEncodingException的檢查可能會顯示一些內容。 –
你怎麼知道它在運行時確實存在? – lakshman
對不起,這是我的錯誤措辭,我的意思是我在運行時出現錯誤,即使該方法確實存在。 – user3237636