我在开发的时候使用webview,在android4.4环境下,第一次进入webview正常,但是到第二次或第三次的时候就会崩溃了。
报错为:
A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.。
java.lang.Throwable: Explicit termination method 'close' not called
初步定为是内存泄露,但是不知道应该怎么回收,在哪儿回收?请大神赐教。
代码如下:
@SuppressLint({ "SetJavaScriptEnabled", "JavascriptInterface" })
public class WebViewActivity extends InstrumentedActivity{
/*************************************************************/
private IWXAPI api;
private WebView webView;
private ProgressBar loadingProgress;
// private ImageView sbtn;
// private TextView address;
public LocationClient mLocationClient = null;
private ValueCallback<Uri> mUploadMessage;
public static String SHARE_IMAGE_PATH;
public BDLocationListener myListener = new MyLocationListener();
InitJPushApplication application;
String url = null;
String path = null;
String pathName = null; // 图片路径
String fileName = null; //图片名称
String subFolder = null;
String username = null;
String password = null;
String imageUri = null;
String imagePath = null;
String rUrl = null; //支付宝订单支付成功后返回的页面地址
int maxWidth,maxHeight;
String subject = null;
String body = null;
String gPrice = null;
String orderNo = null;
String notifyUrl = null;
private final Handler loginHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Intent intent = getIntent();
Bundle bundle = intent.getBundleExtra("bundle");
int id = bundle.getInt("id");
String pushUrl = bundle.getString("pushUrl"); //推送过来的URL
application = (InitJPushApplication) getApplication();
switch (id) {
case R.id.market:
url = Constant.URL_PATH+"/m/";
break;
case R.id.recharge:
url = Constant.URL_PATH+"/m/member_recharge.html";
break;
case R.id.order:
url = Constant.URL_PATH+"/m/member_order.html";
break;
case R.id.mybaihong:
url = Constant.URL_PATH+"/m/member_index.html";
break;
case R.id.prefecture:
url = Constant.URL_PATH+"/m/brand.html";
break;
case R.id.friday:
url = Constant.URL_PATH+"/m/seckill.html";
break;
case R.id.register:
url = Constant.URL_PATH+"/m/register.html";
break;
case R.id.forgetpw:
url = Constant.URL_PATH+"/m/findpassword.html";
break;
case Constant.PUSH_ID:
url = pushUrl;
break;
default:
url = Constant.URL_PATH+"/m/";
break;
}
if(msg.what==200)
{
List<String> cookies = (List<String>) msg.obj;
if(cookies!=null)
{
syncCookieToWebView(cookies);
webView.loadUrl(url);
}
}else if(msg.what==300){
syncCookieToWebView(null);
webView.loadUrl(url);
}else{
super.handleMessage(msg);
}
}
};
private Handler payHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case PaymentUtil.SDK_PAY_FLAG: {
PayResult payResult = new PayResult((String) msg.obj);
// 支付宝返回此次支付结果及加签,建议对支付宝签名信息拿签约时支付宝提供的公钥做验签
String resultInfo = payResult.getResult();
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
if (TextUtils.equals(resultStatus, "9000")) {
Toast.makeText(WebViewActivity.this, "支付成功",
Toast.LENGTH_SHORT).show();
webView.loadUrl(rUrl);
} else {
// 判断resultStatus 为非“9000”则代表可能支付失败
// “8000”代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)
if (TextUtils.equals(resultStatus, "8000")) {
Toast.makeText(WebViewActivity.this, "支付结果确认中",
Toast.LENGTH_SHORT).show();
} else {
// 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误
Toast.makeText(WebViewActivity.this, "支付失败",
Toast.LENGTH_SHORT).show();
}
}
break;
}
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
ShareSDK.initSDK(this); //shareSdk 初始化
setContentView(R.layout.web);
initWebView();
setWebView();
}
private void initWebView() {
webView = (WebView) findViewById(R.id.wv);// 获取控件
loadingProgress = (ProgressBar)findViewById(R.id.progressBar);
// address = (TextView)super.findViewById(R.id.address);
// sbtn = (ImageView) findViewById(R.id.shareButton);
//定位 start
mLocationClient = new LocationClient(getApplicationContext()); //声明LocationClient类
mLocationClient.registerLocationListener(myListener); //注册监听函数
setLocationOption(); //设置参数
// mLocationClient.start();// 开始定位 暂时关闭,用不上
//定位end
//分享 ---注释掉,html页面添加分享按钮,暂时用不到app上添加按钮
// sbtn.setOnClickListener(new OnClickListener() {
//
// public void onClick(View v) {
// // 調用分享方法
// String url = webView.getUrl();
// showShare(url);
// }
// });
new Thread() {
public void run() {
initImagePath();
}
}.start();
}
public void setWebView(){
webView.getSettings().setJavaScriptEnabled(true);// 是否允许加载js文件
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);// 打开缓存
webView.getSettings().setRenderPriority(RenderPriority.HIGH);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAppCacheEnabled(false);
String cacheDirPath = getFilesDir().getAbsolutePath()+Constant.APP_CACAHE_DIRNAME;
webView.getSettings().setDatabasePath(cacheDirPath); //设置数据库缓存路径
webView.getSettings().setAppCachePath(cacheDirPath); //设置application caches 缓存目录
SharedPreferences settings = getSharedPreferences(Constant.PREFS_NAME, Activity.MODE_PRIVATE);
final String Token = settings.getString("LOGIN_INFO", "noToken");
new LoginThread(loginHandler,Token).start();
webView.setWebViewClient(new WebViewClient() {
/**
* 重写shouldOverrideUrlLoading,返回值若为true则用webview,false则是系统自身浏览器
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("tel:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
else{
view.loadUrl(url);
}
return true;
}
});
webView.addJavascriptInterface(new Object(){
@SuppressWarnings("unused")
public String startShare(String wxtitle,String wxdesc,String wxlink,String wximgurl) throws IOException{
showShare(wxlink,wxtitle,wxdesc,wximgurl);
return "baihongshare";
}
@SuppressWarnings("unused")
public String login(String uname,String pwd) throws IOException{
username = uname;
password = pwd;
dologin();
return "baihongshare";
}
@SuppressWarnings("unused")
public String logout() throws IOException{
SharedPreferences settings = getSharedPreferences(Constant.PREFS_NAME, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.clear();
editor.commit();
startActivity(new Intent(getApplication(), BaihongMainActivity.class));
WebViewActivity.this.finish();
return "baihongshare";
}
@SuppressWarnings("unused")
public String upLoadImage(int width,int height,String uploadPath) throws IOException{
maxWidth = width;
maxHeight = height;
subFolder = uploadPath;
Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, Constant.IMAGECHOOSER_RESULTCODE);
return "baihongshare";
}
@SuppressWarnings("unused")
public String upLoadFile(String uploadPath) throws IOException{
subFolder = uploadPath;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("file/*");
WebViewActivity.this.startActivityForResult(
Intent.createChooser(intent, "完成操作需要使用"),
Constant.FILECHOOSER_RESULTCODE);
return "baihongshare";
}
/**
* @param alipayInterface
* H5 页面调用 支付宝支付功能
* @throws IOException
*/
@SuppressWarnings("unused")
public String alipayInterface(String subject,String body,String gPrice,String orderNo,String notifyUrl,String returnUrl) throws IOException{
rUrl = returnUrl;
alipay(subject,body,gPrice,orderNo,notifyUrl);
return "baihongshare";
}
/**
* @param alipayInterface
* H5 页面调用 微信支付功能
* @throws IOException
*/
@SuppressWarnings("unused")
public String wxpayInterface(String subject,String body,String gPrice,String orderNo,String notifyUrl,String returnUrl) throws IOException{
rUrl = returnUrl;
wxpay(subject,body,gPrice,orderNo,notifyUrl);
return "baihongshare";
}
}, "baihongshare");
webView.setWebChromeClient(new WebChromeClient(){
@SuppressWarnings("static-access")
public void onProgressChanged(WebView view ,int progress){
WebViewActivity.this.setProgress(progress * 100);
super.onProgressChanged(view, progress);
if(progress != 100){
loadingProgress.setVisibility(view.VISIBLE);
loadingProgress.setProgress(progress);
}
if (progress == 100) {
loadingProgress.setVisibility(view.GONE);
}
}
/***************** android中使用WebView来打开本机的文件选择器 *************************/
// js上传文件的<input type="file" name="fileField" id="fileField" />事件捕获
// Android < 3.0 调用这个方法
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
WebViewActivity.this.startActivityForResult(
Intent.createChooser(intent, "完成操作需要使用"),
Constant.IMAGECHOOSER_RESULTCODE_NOFILE);
}
// 3.0 + 调用这个方法
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
WebViewActivity.this.startActivityForResult(
Intent.createChooser(intent, "完成操作需要使用"),
Constant.IMAGECHOOSER_RESULTCODE_NOFILE);
}
// Android > 4.1.1 调用这个方法
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
WebViewActivity.this.startActivityForResult(
Intent.createChooser(intent, "完成操作需要使用"),
Constant.IMAGECHOOSER_RESULTCODE_NOFILE);
}
/************** end ***************/
@Override
public boolean onJsAlert(WebView webView, String url,String message, JsResult result){
Log.e("onJsAlert","onJsAlert" + message);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
result.confirm();
return true;
}
@Override
public boolean onJsConfirm(WebView webView,String url,String message, JsResult result){
Log.e("onJsConfirm", "onJsConfirm"+message);
return super.onJsConfirm(webView,url,message,result);
}
@Override
public boolean onJsPrompt(WebView webView, String url,String message,String defaultValue,JsPromptResult result){
Log.e("onJsPrompt", "onJsPrompt"+url);
return super.onJsPrompt(webView, url, message, defaultValue, result);
}
});
}
/**
* cookie同步
*/
private void syncCookieToWebView(List<String> cookies)
{
CookieSyncManager.createInstance(WebViewActivity.this);
CookieManager cm = CookieManager.getInstance();
cm.setAcceptCookie(true);
if(cookies!=null)
{
for (String cookie : cookies)
{
cm.setCookie(Constant.URL_PATH,cookie);//注意端口号和域名,这种方式可以同步所有cookie,包括sessionid
}
}
CookieSyncManager.getInstance().sync();
}
//把图片从drawable复制到sdcard中
private void initImagePath() {
try {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
&& Environment.getExternalStorageDirectory().exists()) {
SHARE_IMAGE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + Constant.FILE_NAME;
}
else {
SHARE_IMAGE_PATH = getApplication().getFilesDir().getAbsolutePath() + Constant.FILE_NAME;
}
File file = new File(SHARE_IMAGE_PATH);
if (!file.exists()) {
file.createNewFile();
Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
FileOutputStream fos = new FileOutputStream(file);
pic.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
}
} catch(Throwable t) {
t.printStackTrace();
SHARE_IMAGE_PATH = null;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == Constant.IMAGECHOOSER_RESULTCODE_NOFILE) {
if (null == mUploadMessage)
return;
Uri result = data == null || resultCode != RESULT_OK ? null
: data.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}else if (requestCode == Constant.IMAGECHOOSER_RESULTCODE) {
if(data != null){
Uri uri = data.getData();
if(uri != null) {
String[] pojo = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, pojo, null, null, null);
if(cursor != null){
int columnIndex = cursor.getColumnIndexOrThrow(pojo[0]); //获得index
cursor.moveToFirst(); //移动到最前面
path = cursor.getString(columnIndex);
cursor.close();
}
if(path != null){
fileName = path.substring(path.lastIndexOf("/") + 1, path.length());
// 判断文件类型
String allowTYpe = "gif,jpg,bmp,png,jpeg";
if (!path.trim().equals("") && path.length() > 0) {
String ex = path.substring(path.lastIndexOf(".") + 1, path.length());
if (allowTYpe.toString().indexOf(ex) < 0) {
Toast.makeText(this, "只能上传gif,jpg,bmp,png格式的图片", Toast.LENGTH_SHORT).show();
return;
}
}
// pathName = path;
try {
new Thread(new Runnable() {
@Override
public void run() {
try {
pathName = BitmapUtils.getThumbUploadPath(path,maxWidth,maxHeight);
doUpload();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}else{
webView.loadUrl("javascript:initPicPath('','')");
}
}else if(requestCode == Constant.FILECHOOSER_RESULTCODE){
// Get the Uri of the selected file
if(null != data){
Uri uri = data.getData();
// String path = getPath(this, uri);
// String path = "";
if("content".equalsIgnoreCase(uri.getScheme())){
String[] pojo = {"_data"};
Cursor cursor = null;
try {
cursor = this.getContentResolver().query(uri, pojo,null, null, null);
int column_index = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) {
path = cursor.getString(column_index);
}
} catch (Exception e) {
// TODO: handle exception
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
path = uri.getPath();
}
if(path != null){
fileName = path.substring(path.lastIndexOf("/") + 1, path.length());
// 判断文件类型
String allowTYpe = "gif,jpg,bmp,swf,png,rar,doc,docx,xls,xlsx,pdf,zip,ico,txt";
if (!path.trim().equals("") && path.length() > 0) {
String ex = path.substring(path.lastIndexOf(".") + 1, path.length());
if (allowTYpe.toString().indexOf(ex) < 0) {
Toast.makeText(this, "不支持此格式文件上传", Toast.LENGTH_SHORT).show();
return;
}
}
try {
new Thread(new Runnable() {
@Override
public void run() {
try {
pathName = path;
doUpload();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}else {
webView.loadUrl("javascript:initPicPath('','')");
}
}
}
private void doUpload(){
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream in = new FileInputStream(pathName);
Map<String,String> data = new HashMap<String,String>();
data.put("subFolder", subFolder);
String result = UploadUtil.UploadImage(in, data,fileName);
if(null != result && !"".equals(result)){
JSONObject json = new JSONObject(EncryptionUtil.decode(result));
String resultMsg = json.getString("result");
if("1".equals(resultMsg)){
imageUri = json.getString("imageUri");
imagePath = json.getString("imagePath");
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i("PATH",imageUri);
webView.loadUrl("javascript:initPicPath('"+imagePath+"','"+imageUri+"')");
Toast.makeText(WebViewActivity.this, "上传成功", Toast.LENGTH_SHORT).show();
}
});
// 判断文件类型
String allowTYpe = "gif,jpg,bmp,png";
if (!pathName.trim().equals("") && pathName.length() > 0) {
String ex = pathName.substring(pathName.lastIndexOf(".") + 1, pathName.length());
if (allowTYpe.toString().indexOf(ex) < 0) {
}else{
File file = new File(pathName);
if(file.exists()){
file.delete();
}
}
}
}else{
Log.e("pic", resultMsg);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WebViewActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
}
});
}
}else{
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WebViewActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
}
});
}
} catch (Exception e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WebViewActivity.this, "上传失败", Toast.LENGTH_SHORT).show();
}
});
e.printStackTrace();
System.out.print(e);
}
}
}).start();
}
private void dologin(){
new Thread(new Runnable() {
@Override
public void run() {
String regID = JPushInterface.getRegistrationID(getApplication());
String loginkey = EncryptionUtil.encode("{\"username\":\""+username+"\",\"password\":\""+password+"\",\"regID\":\""+regID+"\"," +
"\"appType\":\""+Constant.APP_TYPE+"\",\"bizType\":\""+Constant.BIZ_TYPE+"\"}");
String url = Constant.URL_PATH+"/widget";
String params = "type=member_login&ajax=yes&action=remotelogin&loginkey="+loginkey;
String resultBeforeDecode = HttpUtil.doPost(url, params, "utf-8");
if(resultBeforeDecode.equals("timeout")){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(WebViewActivity.this, "请求超市,请稍后重试", Toast.LENGTH_SHORT).show();
}
});
return;
}
String resultMsg = EncryptionUtil.decode(resultBeforeDecode);
Gson gson = new Gson();
User user = gson.fromJson(resultMsg, User.class);
if(user.getResult().equals("1")){
String Token = EncryptionUtil.encode("{\"username\":\""+user.getUsername()+"\",\"password\":\""+user.getPassword()+"\",\"regID\":\""+user.getRegID()+"\",\"appType\":\""+Constant.APP_TYPE+"\",\"bizType\":\""+Constant.BIZ_TYPE+"\"}");
SharedPreferences settings = getSharedPreferences(Constant.PREFS_NAME, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = settings.edit();
editor.putString("LOGIN_INFO", Token);
editor.putString("USER_INFO", resultMsg);
editor.commit();
}
}
}).start();
}
/**
* 支付宝支付
* @param gName 商品名称
* @param gDesc 商品描述
* @param gPrice 商品价格
* @param orderNo 订单号
*/
public void alipay(String subject,String body,String gPrice,String orderNo,String notifyUrl){
// 订单
String orderInfo = PaymentUtil.getOrderInfo(subject,body,gPrice,orderNo,notifyUrl);
// 对订单做RSA 签名
String sign = PaymentUtil.sign(orderInfo);
try {
// 仅需对sign 做URL编码
sign = URLEncoder.encode(sign, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 完整的符合支付宝参数规范的订单信息
final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"
+ PaymentUtil.getSignType();
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 构造PayTask 对象
PayTask alipay = new PayTask(WebViewActivity.this);
// 调用支付接口,获取支付结果
String result = alipay.pay(payInfo);
Message msg = new Message();
msg.what = PaymentUtil.SDK_PAY_FLAG;
msg.obj = result;
payHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
/**
* 支付宝支付
* @param gName 商品名称
* @param gDesc 商品描述
* @param gPrice 商品价格
* @param orderNo 订单号
*/
public void wxpay(String subject,String body,String gPrice,String orderNo,String notifyUrl){
api = WXAPIFactory.createWXAPI(this, Constant.APP_ID);
api.registerApp(Constant.APP_ID);
this.subject = subject;
this.body = body;
this.gPrice = gPrice;
this.orderNo = orderNo;
this.notifyUrl = notifyUrl;
new GetAccessTokenTask().execute();
}
private void setLocationOption() {
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);
option.setIsNeedAddress(true); // 返回的定位结果包含地址信息
option.setAddrType("all"); // 返回的定位结果包含地址信息
option.setCoorType("bd09ll"); // 返回的定位结果是百度经纬度,默认值gcj02
option.setScanSpan(5000); // 设置发起定位请求的间隔时间为5000ms
mLocationClient.setLocOption(option);
}
public class MyLocationListener implements BDLocationListener {
public void onReceiveLocation(BDLocation location) {
if (location == null)
return;
StringBuffer sb = new StringBuffer(256);
if (location.getLocType() == BDLocation.TypeNetWorkLocation) {
//sb.append("当前位置 : ");
//sb.append(location.getAddrStr());
//sb.append(location.getCity());
sb.append(location.getDistrict());
sb.append(location.getStreet());
sb.append(location.getStreetNumber());
}
//address.setText(sb.toString());
}
public void onReceivePoi(BDLocation poiLocation) {
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {// keyCode代表按键的数字标示符
Intent intent = getIntent();
Bundle bundle = intent.getBundleExtra("bundle");
String key = bundle.getString("key");
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView.canGoBack()) {
webView.goBack();
return true;
} else if (null != key && key.equals("webview"))
{
intent.setClass(WebViewActivity.this, BaihongMainActivity.class);
startActivity(intent);
WebViewActivity.this.finish();
}else {
System.exit(0);
}
}
return super.onKeyDown(keyCode, event);
}
//share 调用OneKeyShare
private void showShare(String wxlink, String wxtitle, String wxdesc, String wximgurl) {
OnekeyShare oks = new OnekeyShare();
//关闭sso授权
oks.disableSSOWhenAuthorize();
//分享时Notification的图标和文字 ,Notification是一种状态栏的提示
oks.setNotification(R.drawable.icon, getString(R.string.app_name));
// title标题,印象笔记、邮箱、信息、微信、人人网和QQ空间使用
oks.setTitle(wxtitle);
// titleUrl是标题的网络链接,仅在人人网和QQ空间使用
oks.setTitleUrl(wxlink);
// text是分享文本,所有平台都需要这个字段
oks.setText(wxdesc+":"+wxlink);
// imagePath是图片的本地路径,Linked-In以外的平台都支持此参数
//oks.setImagePath(WebViewActivity.TEST_IMAGE);//确保SDcard下面存在此张图片
oks.setImageUrl(wximgurl);
// url仅在微信(包括好友和朋友圈)中使用
oks.setUrl(wxlink);
// comment是我对这条分享的评论,仅在人人网和QQ空间使用
oks.setComment(wxdesc);
// site是分享此内容的网站名称,仅在QQ空间使用
oks.setSite(getString(R.string.baihong_portal));
// siteUrl是分享此内容的网站地址,仅在QQ空间使用
oks.setSiteUrl(wxlink);
// 启动分享GUI
oks.show(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();// 停止定位
ShareSDK.stopSDK();
webView.clearHistory();
webView.clearCache(true);
}
private class GetAccessTokenTask extends AsyncTask<Void, Void, GetAccessTokenResult> {
private ProgressDialog dialog;
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(GetAccessTokenResult result) {
if (dialog != null) {
dialog.dismiss();
}
if (result.localRetCode == LocalRetCode.ERR_OK) {
Log.d("wxpay-getToken", "onPostExecute, accessToken = " + result.accessToken);
GetPrepayIdTask getPrepayId = new GetPrepayIdTask(result.accessToken);
getPrepayId.execute();
}
}
@Override
protected GetAccessTokenResult doInBackground(Void... params) {
GetAccessTokenResult result = new GetAccessTokenResult();
String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
Constant.APP_ID, Constant.APP_SECRET);
Log.d("wxpay-GetAccessTokenResult", "get access token, url = " + url);
byte[] buf = WxPayUtil.httpGet(url);
if (buf == null || buf.length == 0) {
result.localRetCode = LocalRetCode.ERR_HTTP;
return result;
}
String content = new String(buf);
result.parseFrom(content);
return result;
}
}
private class GetPrepayIdTask extends AsyncTask<Void, Void, GetPrepayIdResult> {
private ProgressDialog dialog;
private String accessToken;
public GetPrepayIdTask(String accessToken) {
this.accessToken = accessToken;
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(GetPrepayIdResult result) {
if (dialog != null) {
dialog.dismiss();
}
if (result.localRetCode == LocalRetCode.ERR_OK) {
sendPayReq(result);
}
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected GetPrepayIdResult doInBackground(Void... params) {
String url = String.format("https://api.weixin.qq.com/pay/genprepay?access_token=%s", accessToken);
String entity = genProductArgs();
Log.d("wxpay-GetPrepayIdResult", "doInBackground, url = " + url);
Log.d("wxpay-GetPrepayIdResult", "doInBackground, entity = " + entity);
GetPrepayIdResult result = new GetPrepayIdResult();
byte[] buf = WxPayUtil.httpPost(url, entity);
if (buf == null || buf.length == 0) {
result.localRetCode = LocalRetCode.ERR_HTTP;
return result;
}
String content = new String(buf);
Log.d("wxpay-GetPrepayIdResult", "doInBackground, content = " + content);
result.parseFrom(content);
return result;
}
}
private static enum LocalRetCode {
ERR_OK, ERR_HTTP, ERR_JSON, ERR_OTHER
}
private static class GetAccessTokenResult {
private static final String TAG = "MicroMsg.SDKSample.PayActivity.GetAccessTokenResult";
public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER;
public String accessToken;
public int expiresIn;
public int errCode;
public String errMsg;
public void parseFrom(String content) {
if (content == null || content.length() <= 0) {
Log.e(TAG, "parseFrom fail, content is null");
localRetCode = LocalRetCode.ERR_JSON;
return;
}
try {
JSONObject json = new JSONObject(content);
if (json.has("access_token")) { // success case
accessToken = json.getString("access_token");
expiresIn = json.getInt("expires_in");
localRetCode = LocalRetCode.ERR_OK;
} else {
errCode = json.getInt("errcode");
errMsg = json.getString("errmsg");
localRetCode = LocalRetCode.ERR_JSON;
}
} catch (Exception e) {
localRetCode = LocalRetCode.ERR_JSON;
}
}
}
private static class GetPrepayIdResult {
private static final String TAG = "MicroMsg.SDKSample.PayActivity.GetPrepayIdResult";
public LocalRetCode localRetCode = LocalRetCode.ERR_OTHER;
public String prepayId;
public int errCode;
public String errMsg;
public void parseFrom(String content) {
if (content == null || content.length() <= 0) {
Log.e(TAG, "parseFrom fail, content is null");
localRetCode = LocalRetCode.ERR_JSON;
return;
}
try {
JSONObject json = new JSONObject(content);
if (json.has("prepayid")) { // success case
prepayId = json.getString("prepayid");
localRetCode = LocalRetCode.ERR_OK;
} else {
localRetCode = LocalRetCode.ERR_JSON;
}
errCode = json.getInt("errcode");
errMsg = json.getString("errmsg");
} catch (Exception e) {
localRetCode = LocalRetCode.ERR_JSON;
}
}
}
private String genNonceStr() {
Random random = new Random();
return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
}
private long genTimeStamp() {
return System.currentTimeMillis() / 1000;
}
/**
* 建议 traceid 字段包含用户信息及订单信息,方便后续对订单状态的查询和跟踪
*/
private String getTraceId() {
return "crestxu_" + genTimeStamp();
}
private long timeStamp;
private String nonceStr, packageValue;
private String genSign(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
int i = 0;
for (; i < params.size() - 1; i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
String sha1 = WxPayUtil.sha1(sb.toString());
Log.d("wxpay-genOutTradNo", "genSign, sha1 = " + sha1);
return sha1;
}
private String genPackage(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue());
sb.append('&');
}
sb.append("key=");
sb.append(Constant.PARTNER_KEY); // 注意:不能hardcode在客户端,建议genPackage这个过程都由服务器端完成
// 进行md5摘要前,params内容为原始内容,未经过url encode处理
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return URLEncodedUtils.format(params, "utf-8") + "&sign=" + packageSign;
}
private String genProductArgs() {
JSONObject json = new JSONObject();
try {
json.put("appid", Constant.APP_ID);
String traceId = getTraceId(); // traceId 由开发者自定义,可用于订单的查询与跟踪,建议根据支付用户信息生成此id
json.put("traceid", traceId);
nonceStr = genNonceStr();
json.put("noncestr", nonceStr);
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("bank_type", "WX"));
packageParams.add(new BasicNameValuePair("body", body));
packageParams.add(new BasicNameValuePair("fee_type", "1"));
packageParams.add(new BasicNameValuePair("input_charset", "UTF-8"));
packageParams.add(new BasicNameValuePair("notify_url", notifyUrl));
packageParams.add(new BasicNameValuePair("out_trade_no", orderNo));
packageParams.add(new BasicNameValuePair("partner", Constant.PARTNER_ID));
packageParams.add(new BasicNameValuePair("spbill_create_ip", getLocalIpAddress()));
packageParams.add(new BasicNameValuePair("total_fee", gPrice));
packageValue = genPackage(packageParams);
json.put("package", packageValue);
timeStamp = genTimeStamp();
json.put("timestamp", timeStamp);
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", Constant.APP_ID));
signParams.add(new BasicNameValuePair("appkey", Constant.APP_KEY));
signParams.add(new BasicNameValuePair("noncestr", nonceStr));
signParams.add(new BasicNameValuePair("package", packageValue));
signParams.add(new BasicNameValuePair("timestamp", String.valueOf(timeStamp)));
signParams.add(new BasicNameValuePair("traceid", traceId));
json.put("app_signature", genSign(signParams));
json.put("sign_method", "sha1");
} catch (Exception e) {
Log.e("wxpay-genProductArgs", "genProductArgs fail, ex = " + e.getMessage());
return null;
}
return json.toString();
}
private void sendPayReq(GetPrepayIdResult result) {
PayReq req = new PayReq();
req.appId = Constant.APP_ID;
req.partnerId = Constant.PARTNER_ID;
req.prepayId = result.prepayId;
req.nonceStr = nonceStr;
req.timeStamp = String.valueOf(timeStamp);
req.packageValue = "Sign=" + packageValue;
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("appkey", Constant.APP_KEY));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
req.sign = genSign(signParams);
// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
api.sendReq(req);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
/**
*获得客户端真实IP地址的方法
* @return
*/
public String getLocalIpAddress() {
String ip = "";
ConnectivityManager connectMgr = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectMgr.getActiveNetworkInfo();
if(info != null){
if(info.getType() == ConnectivityManager.TYPE_WIFI){
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
//判断wifi是否开启
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipAddress = wifiInfo.getIpAddress();
ip = formatIpAddress(ipAddress);
return ip;
}else if(info.getType() == ConnectivityManager.TYPE_MOBILE){
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
ip = inetAddress.getHostAddress().toString();
}
}
}
} catch (SocketException ex) {
Log.e("getLocalIpAddress", ex.toString());
}
}
}else {
ip = "127.0.0.1";
}
return ip;
}
private static String formatIpAddress(int ipAdress) {
return (ipAdress & 0xFF ) + "." +
((ipAdress >> 8 ) & 0xFF) + "." +
((ipAdress >> 16 ) & 0xFF) + "." +
( ipAdress >> 24 & 0xFF) ;
}
}
扫了一遍代码,有可能是因为这个泄露了。
应该在
finally
里面关闭。