我一直在尝试将我的Android应用与Microsoft Translator API连接,我已经在Windows Azure Marketplace中注册了我的应用。但是当我运行我的应用程序时,我在打开应用程序时一直遇到IOException。
04-17 21:18:15.661: E/TranslateTask(274): IOException
04-17 21:18:15.661: E/TranslateTask(274): javax.net.ssl.SSLException: Not trusted server certificate
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:371)
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.getSecureSocket(HttpConnection.java:168)
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:399)
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:147)
04-17 21:18:15.661: E/TranslateTask(274): at ac.lk.iit.androidtranslatorproject.TranslateActivity$GetAccessTokenTask.doInBackground(TranslateActivity.java:212)
04-17 21:18:15.661: E/TranslateTask(274): at ac.lk.iit.androidtranslatorproject.TranslateActivity$GetAccessTokenTask.doInBackground(TranslateActivity.java:1)
04-17 21:18:15.661: E/TranslateTask(274): at android.os.AsyncTask$2.call(AsyncTask.java:185)
04-17 21:18:15.661: E/TranslateTask(274): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
04-17 21:18:15.661: E/TranslateTask(274): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
04-17 21:18:15.661: E/TranslateTask(274): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
04-17 21:18:15.661: E/TranslateTask(274): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
04-17 21:18:15.661: E/TranslateTask(274): at java.lang.Thread.run(Thread.java:1096)
04-17 21:18:15.661: E/TranslateTask(274): Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:168)
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:366)
04-17 21:18:15.661: E/TranslateTask(274): ... 11 more
04-17 21:18:15.661: E/TranslateTask(274): Caused by: java.security.cert.CertPathValidatorException: TrustAnchor for CertPath not found.
04-17 21:18:15.661: E/TranslateTask(274): at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:149)
04-17 21:18:15.661: E/TranslateTask(274): at java.security.cert.CertPathValidator.validate(CertPathValidator.java:202)
04-17 21:18:15.661: E/TranslateTask(274): at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:164)
04-17 21:18:15.661: E/TranslateTask(274): ... 12 more
此外,以下是该应用程序的相关文件。
TranslateActivity.java
package ac.lk.iit.androidtranslatorproject;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
public class TranslateActivity extends Activity {
private static final String TAG = "TranslateTask";
private Spinner fromSpinner;
private Spinner toSpinner;
private EditText origText;
private TextView transText;
private Button transButton;
private String fromLang;
private String toLang;
private TextWatcher textWatcher;
private OnItemSelectedListener itemListener;
private OnClickListener buttonListener;
// needed to make translate requests to Microsoft
private String accessToken;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_translate);
findViews();
setAdapters();
setListeners();
// get the access token from Microsoft
new GetAccessTokenTask().execute();
}
private void findViews() {
fromSpinner = (Spinner) findViewById(R.id.from_language);
toSpinner = (Spinner) findViewById(R.id.to_language);
origText = (EditText) findViewById(R.id.original_text);
transText = (TextView) findViewById(R.id.translated_text);
transButton = (Button) findViewById(R.id.translate_button);
}
/** Define data source for the spinners */
private void setAdapters() {
// Spinner list comes from a resource,
// Spinner user interface uses standard layouts
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.languages,android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
fromSpinner.setAdapter(adapter);
toSpinner.setAdapter(adapter);
// Automatically select two spinner items
fromSpinner.setSelection(8); // English (en)
toSpinner.setSelection(25); // Spanish (es)
}
private void setListeners() {
textWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s,int start, int count,int after) {
}
public void onTextChanged(CharSequence s,int start, int before,int count) {
/*doTranslate2(origText.getText().toString().trim(),fromLang, toLang); */
}
public void afterTextChanged(Editable s) {
}};
origText.addTextChangedListener(textWatcher);
itemListener = new OnItemSelectedListener() {
public void onItemSelected(AdapterView parent, View v,int position, long id) {
fromLang = getLang(fromSpinner);
toLang = getLang(toSpinner);
if (accessToken != null)
doTranslate2(origText.getText().toString().trim(), fromLang, toLang);
}
public void onNothingSelected(AdapterView parent) {
/* Do nothing */
}};
fromSpinner.setOnItemSelectedListener(itemListener);
toSpinner.setOnItemSelectedListener(itemListener);
buttonListener = new OnClickListener() {
public void onClick(View v) {
if (accessToken != null)
System.out.println(accessToken);
doTranslate2(origText.getText().toString().trim(), fromLang, toLang);
}};
transButton.setOnClickListener(buttonListener);
}
/** Extract the language code from the current spinner item */
private String getLang(Spinner spinner) {
String result = spinner.getSelectedItem().toString();
int lparen = result.indexOf('(');
int rparen = result.indexOf(')');
result = result.substring(lparen + 1, rparen);
return result;
}
private void doTranslate2(String original,String from, String to) {
if (accessToken != null)
new TranslationTask().execute(original, from, to);
}
private class TranslationTask extends AsyncTask<String,Void,String> {
protected void onPostExecute(String translation) {
transText.setText(translation);
}
protected String doInBackground(String... s) {
HttpURLConnection con2 = null;
String result = getResources().getString(
R.string.translation_error);
String original = s[0];
String from = s[1];
String to = s[2];
try {
// Read results from the query
BufferedReader reader;
String uri = "http://api.microsofttranslator.com" + "/v2/Http.svc/Translate?text=" + URLEncoder.encode(original) +"&from=" + from + "&to=" + to;
URL url_translate = new URL(uri);
String authToken = "Bearer" + " " + accessToken;
con2 = (HttpURLConnection) url_translate.
openConnection();
con2.setRequestProperty("Authorization", authToken);
con2.setDoInput(true);
con2.setReadTimeout(10000 /* milliseconds */);
con2.setConnectTimeout(15000 /* milliseconds */);
reader = new BufferedReader(new InputStreamReader(
con2.getInputStream(), "UTF-8"));
String translated_xml = reader.readLine();
reader.close();
/* translated_xml now contains the following XML:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hola</string> */
// parse the XML returned
DocumentBuilder builder = DocumentBuilderFactory.
newInstance().newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(translated_xml)));
NodeList node_list = doc.getElementsByTagName("string");
NodeList l = node_list.item(0).getChildNodes();
Node node;
String translated = null;
if (l != null && l.getLength() > 0) {
node = l.item(0);
translated = node.getNodeValue();
}
if (translated != null)
result = translated;
} catch (IOException e) {
Log.e(TAG, "IOException", e);
} catch (SAXException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
finally {
if (con2 != null) {
con2.disconnect();
}
}
return result;
}
}
private class GetAccessTokenTask extends AsyncTask<Void, Void, String> {
protected void onPostExecute(String access_token) {
accessToken = access_token;
}
protected String doInBackground(Void... v) {
String result = null;
HttpURLConnection con = null;
String clientID = "<client id>";
String clientSecret = "<client secret>";
String strTranslatorAccessURI ="https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
String strRequestDetails = "grant_type=" + "client_credentials&client_id=" + URLEncoder.encode(clientID) + "&client_secret="+ URLEncoder.encode(clientSecret) + "&scope=http://api.microsofttranslator.com";
try {
URL url = new URL(strTranslatorAccessURI);
con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(10000 /* milliseconds */);
con.setConnectTimeout(15000 /* milliseconds */);
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setChunkedStreamingMode(0);
// Start the query
con.connect();
OutputStream out = new BufferedOutputStream(con.getOutputStream());
out.write(strRequestDetails.getBytes());
out.flush();
// Read results from the query
BufferedReader reader = new BufferedReader(
new InputStreamReader(con.getInputStream(), "UTF-8"));
String payload = reader.readLine();
reader.close();
out.close();
/* payload now contains JSON attribute value pairs:
{"token_type":"http://schemas.xmlsoap.org/ws/2009/
11/swt-token-profile-1.0","access_token":"....",
"expires_in":"600","scope":
"http://api.microsofttranslator.com"} */
// Parse to get the access token
JSONObject jsonObject = new JSONObject(payload);
result = jsonObject.getString("access_token");
} catch (IOException e) {
Log.e(TAG, "IOException", e);
} catch (JSONException e) {
Log.e(TAG, "JSONException", e);
} finally {
if (con != null) {
con.disconnect();
}
}
return result;
}
}
}
我没有提到客户端ID和秘密但是错误似乎是从doInBackground方法中抛出的,并且确切地说是方法调用connect()的点。
以下是活动的布局页面。
activity_translate.xml
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1"
android:padding="10dip">
<TableRow>
<TextView android:text="@string/from_text" />
<Spinner android:id="@+id/from_language" />
</TableRow>
<EditText
android:id="@+id/original_text"
android:hint="@string/original_hint"
android:padding="10dip"
android:textSize="18sp" />
<TableRow>
<TextView android:text="@string/to_text" />
<Spinner android:id="@+id/to_language" />
</TableRow>
<TextView
android:id="@+id/translated_text"
android:padding="10dip"
android:textSize="18sp" />
<Button
android:id="@+id/translate_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Translate"
android:layout_gravity="center" />
</TableLayout>
</ScrollView>
我还确保在应用清单文件中启用了使用互联网的许可。
如果有人能帮助我找到解决这个问题的方法,我将不胜感激,因为这对我来说是一个全新的领域,如果上述错误的原因也能得到清楚解释,我将不胜感激。请原谅我因为在我刚接触这个研究领域之前提到的任何错误。
答案 0 :(得分:0)
我不知道第三方库是否可以在这种情况下提供帮助,但使用OkHTTP库帮助我修复了一些很少出现在我的应用程序中的SSL证书的错误。 https://github.com/square/okhttp