Android google翻译踩坑之旅

#

Android google翻译踩坑之旅

  最近由于工作需求,需要为游戏Android平台接入Google翻译的SDK,由于关于翻译的文章非常少,访问官方文档又需要翻墙,更可气的是找到的博客写了一大堆结果是错的,官网给的库跟链接也不对,导致耽搁了挺长一段时间。今天我就分享下我的踩坑之旅,希望这篇博客能帮助到也需要接Google翻译的人。

  废话不多说,首先使用Google翻译是需要翻墙的,请自备VPN。关于怎么注册申请翻译API请看这篇博客需要注意的一点是Android平台需要申请参数APIKey,在申请时是需要选择Android apps 并需要填入应用包名 和应用签名的SHA1字符串的,假如你申请时没有填入这两项,那你申请的可能不是Android的翻译API。

  参数申请完毕后还需要下载一个jar包 guava.jar点这进入下载页。本来我是看了这篇博客进行接入的 http://blog.csdn.net/nicolelili1/article/details/76973097 ,由于公司项目是eclipse工程,我把依赖里的jar包全部下载,放到工程里大概10M左右,并且方法数超出65535限制,使用dex分包方案后测试发现翻译失败,Log打印错误日志如下:

{
    "code": 403,
    "errors": [{
        "domain": "global",
        "message": "Requests from this Android client application <empty> are blocked.",
        "reason": "forbidden"
    }],
    "message": "Requests from this Android client application <empty> are blocked.",
    "status": "PERMISSION_DENIED"
}

在 stackoverflow 上看到一个一模一样的问题,看了半天发现说的不是翻译。。。然后接着换了关键词去搜,发现这里有一个回答有点靠谱,一个老外发的帖子说自己用OKHttp接入谷歌翻译出错,虽然错误内容不一样,但有个回复引起了我的注意:

大概意思是说在调用 Google翻译URL进行翻译时需要在请求头加上"X-Android-Package" 包名和"X-Android-Cert"应用签名SHA1然后给了获取SHA1的示例代码:


/**
 * Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
 *
 * @param packageName Identifies the APK whose signature should be extracted.
 * @return a lowercase, hex-encoded
 */
public static String getSignature(@NonNull PackageManager pm, @NonNull String packageName) {
    try {
        PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
        if (packageInfo == null
                || packageInfo.signatures == null
                || packageInfo.signatures.length == 0
                || packageInfo.signatures[0] == null) {
            return null;
        }
        return signatureDigest(packageInfo.signatures[0]);
    } catch (PackageManager.NameNotFoundException e) {
        return null;
    }
}

private static String signatureDigest(Signature sig) {
    byte[] signature = sig.toByteArray();
    try {
        MessageDigest md = MessageDigest.getInstance("SHA1");
        byte[] digest = md.digest(signature);
        return BaseEncoding.base16().lowerCase().encode(digest);
    } catch (NoSuchAlgorithmException e) {
        return null;
    }
}

以及如何使用HttpulrConnection进行正确的请求:

java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
    connection.setDoInput(true);
    connection.setDoOutput(true);

    connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
    connection.setRequestProperty("Accept", "application/json");

    // add package name to request header
    String packageName = mActivity.getPackageName();
    connection.setRequestProperty("X-Android-Package", packageName);
    // add SHA certificate to request header
    String sig = getSignature(mActivity.getPackageManager(), packageName);
    connection.setRequestProperty("X-Android-Cert", sig);
    connection.setRequestMethod("POST");

    // ADD YOUR REQUEST BODY HERE
    // ....................
} catch (Exception e) {
    e.printStackTrace();
} finally {
    connection.disconnect();
}

在此基础上我写了Demo进行测试,不过网络框架我是用的OkHttp,在有VPN的情况下是可以翻译成功的,没有VPN可能会报链接超时的错误。由于需要分dex,我把代码打成了jar包: 源码下载 jar包下载

其实就是使用链接访问google翻译API,Google翻译链接地址是这个: https://www.googleapis.com/language/translate/v2 其中需要传入几个参数:

  • key:apiKey
  • target:目标语言(en zh等语言代号)
  • q:要翻译的内容(该参数是可以传递多个的,如:…url?q=内容&q=测试)

以及要在请求头加上 X-Android-Package 和 X-Android-Cert 信息,只要参数传递无误,并且有翻墙软件开启,得到的翻译结果格式如下:

{
 "data": {
   "translations": [
	 {
	   "translatedText": "test",
	   "detectedSourceLanguage": "zh-CN"
	 }
   ]
 }
}

translatedText 就是翻译结果,detectedSourceLanguage是
考虑到有的朋友不能访问github下载代码,在此处贴入具体代码:

public class OkHttpFactory {
	private static OkHttpClient okHttpClient;
	public static OkHttpClient getOkHttpClient(){
		if(okHttpClient == null){
			synchronized (OkHttpFactory.class){
				if(okHttpClient == null){
					okHttpClient = new OkHttpClient.Builder()
							.connectTimeout(20, TimeUnit.SECONDS)
							.build();
				}
			}
		}
		return okHttpClient;
	}
}
public interface TranslationCallback {
	void onTranslationSuccess(String resultJson);
	void onTranslationFailed(String errMsg);
}
public class Translation {
	private String apiKey = "";
	private static String REQUEST_URL = "https://www.googleapis.com/language/translate/v2";
	private static String PACKAGE_KEY = "X-Android-Package";
	private static String SHA1_KEY = "X-Android-Cert";
	public Translation(String apiKey){
		this.apiKey = apiKey;
	}

	public void translate(Context context,String content,String targetLanguage, TranslationCallback callback){
		JSONArray array = new JSONArray();
		array.put(content);
		translate(context,array,targetLanguage,callback);
	}
	public void translate(Context context, JSONArray contents, String targetLanguage, final TranslationCallback callback){
		OkHttpClient okHttpClient = OkHttpFactory.getOkHttpClient();
		String sig = getSignature(context.getPackageManager(),context.getPackageName());
		FormBody.Builder builder = new FormBody.Builder()
				.add("key", apiKey)
				.add("target", targetLanguage);
		for (int i = 0; i < contents.length(); i++) {
			String text;
			try {
				text = contents.getString(i);
				builder.add("q",text);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		FormBody formBody = builder.build();
		Request request = new Request.Builder()
				.url(REQUEST_URL)
				.header(PACKAGE_KEY,context.getPackageName())
				.header(SHA1_KEY,sig)
				.post(formBody)
				.build();
		Call call = okHttpClient.newCall(request);
		call.enqueue(new Callback() {
			@Override
			public void onFailure(Call call, IOException e) {
				callback.onTranslationFailed(e == null?"null":e.getMessage());
			}
			@Override
			public void onResponse(Call call, Response response) throws IOException {
				callback.onTranslationSuccess(response.body().string());
			}
		});
	}
	/**
	 * Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
	 *
	 * @param packageName Identifies the APK whose signature should be extracted.
	 * @return a lowercase, hex-encoded
	 */
	private static String getSignature(PackageManager pm, String packageName) {
		try {
			PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
			if (packageInfo == null
					|| packageInfo.signatures == null
					|| packageInfo.signatures.length == 0
					|| packageInfo.signatures[0] == null) {
				return null;
			}
			return signatureDigest(packageInfo.signatures[0]);
		} catch (PackageManager.NameNotFoundException e) {
			return null;
		}
	}

	private static String signatureDigest(Signature sig) {
		byte[] signature = sig.toByteArray();
		try {
			MessageDigest md = MessageDigest.getInstance("SHA1");
			byte[] digest = md.digest(signature);
			return BaseEncoding.base16().lowerCase().encode(digest);
		} catch (NoSuchAlgorithmException e) {
			return null;
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值