Android之微信接入分享,登录功能。
2015-11-07 15:36
731 查看
最近在做一个APP项目,需要用到微信分享啊,登录这些。
微信支付的参考另外一篇:Android之微信支付功能
还有开发工具包(第一个),然后将签名生成工具安装到我们的机器上。微信的这个东西百度很难找,我把地址转为二维码,用手机扫描打开然后下载吧。
优点:方便快捷,只需直接输入包名即可。
缺点:该签名只在当时的手机上有效,在其它手机上无效。
优点:可以让该应用在任何手机上都可以调用微信的功能。
缺点:也不算什么缺点,就是要注意签名过程中的一些东西,这个请另行查找,步骤比较琐碎。
1.填写基本信息:
2.填写平台信息:官网如果没有的话可以随便填,我填的是www.baidu.com~,应用签名就是我们刚才获取到的那一长串,应用包名也是之前填写的包名。
3.提交审核,静候佳音。
4.审核成功后,我们就会得到AppID和APPSecret:(注意此时你只能拥有微信分享的功能,关于微信登录的功能你需要去进行开发者认证,叫三百块,填写一些企业的相关内容这样)
import com.tencent.mm.sdk.openapi.WXTextObject;
新建完WXEntryActivity后,要切记进行注册!! 尤其是写上android:exported="true"
你需要实现IWXAPIEventHandler接口,然后去重写onReq()方法和onResp()方法。另外切记要注意的,如果当你重写了这两个方法后,发现为什么点击了还是没有相关我们想要的操作的时候,你就很有可能没写:MyApplication.api.handleIntent(getIntent(), this);
接下来就是那几步操作了,你可以结合微信开发文档看看。
(1)获取code,用户点击同意授权后,会返回一个code的给你,在onResp()方法里进行。
在这里我们要注意这行代码 :
这里因为处理的是登录请求,所以我们将BaseResp强制转换为符合SenAuth,但如果你只是在onResp()方法里这样写的话,那么你的分享功能就应该会出错了,或者说可以分享成功,但返回APP的时候它会报错。因为此时你的BaseResp没有做分享信息回调的处理。
你可能会以为当时一开始做微信分享功能的时候,压根就没有用到WXEntryActivity啊,其实它是有用到的,而且当时也默认处理了你的分享回调的信息。所以我们可能会以为做分享信息只要写上发信息的代码就行了,但这只是一部分而已。
那么为了解决这个问题,你就要对BaseResp做判断了,因为你如果重新回去看微信的文档,就发现在BaseResp里有一个getType()方法,它就是显示你当前发送请求信息后返回的相应类型,那么你现在可以进入ConstantsAPI里去查看它所支持的类型有哪些。
我们可以看到这两个就是我们这里要的,一个是处理登录验证,一个是分享消息
然后点击进去后你就会看到它们相应的数值,处理登录类型的数值为1,处理分享消息类型的数值为2,所以你就要通过对它们数值的判断来作相应的处理了。
以下是我的完整的代码
后面附上我用的通用网络请求
回调接口:
注:以上两段代码来自郭霖老师的《第一行代码》
微信支付的参考另外一篇:Android之微信支付功能
微信支付的参考另外一篇:Android之微信支付功能
1 前期准备
1.1 下载签名生成工具和SDK包
去微信:https://open.weixin.qq.com/cgi-bin/readtemplate?t=resource/app_download_android_tmpl&lang=zh_CN下载签名生成工具还有开发工具包(第一个),然后将签名生成工具安装到我们的机器上。微信的这个东西百度很难找,我把地址转为二维码,用手机扫描打开然后下载吧。
1.2获取应用签名
1.2.1 未签名应用
将我们的程序运行在手机上后,打开签名生成工具,输入我们应用的包名,这个可以在我们工程的Manifest.xml文件里看到,然后就可以得到签名。优点:方便快捷,只需直接输入包名即可。
缺点:该签名只在当时的手机上有效,在其它手机上无效。
1.2.2 已签名应用
先对我们的程序进行打包和签名,我为了方便就在打包签名的时候给它起名为debug.keystore,密码为android,alias为androiddebugkey,这样的方便就在于能够直接在eclipse里通过Window——preferences——Android——bulid里的Custom debug keystore里去引用查看,点击apply。当然你也可以签名后,安装到手机上,同样的用微信签名生成工具查看签名,这里的签名是MD5签名,填写的时候不用添加冒号“:”。优点:可以让该应用在任何手机上都可以调用微信的功能。
缺点:也不算什么缺点,就是要注意签名过程中的一些东西,这个请另行查找,步骤比较琐碎。
1.3 微信开放平台创建应用
获取到我们的签名后,就进入微信开放平台,先注册一个账号,然后就创建我们的应用:1.填写基本信息:
2.填写平台信息:官网如果没有的话可以随便填,我填的是www.baidu.com~,应用签名就是我们刚才获取到的那一长串,应用包名也是之前填写的包名。
3.提交审核,静候佳音。
4.审核成功后,我们就会得到AppID和APPSecret:(注意此时你只能拥有微信分享的功能,关于微信登录的功能你需要去进行开发者认证,叫三百块,填写一些企业的相关内容这样)
2 开发工作:
2.1 导入jar包
解压我们下载好的开发工具包,将里面的libammsdk.jar拉到我们的libs文件夹里,然后右键工程——Build Path——Config Build Path——Libraries——ADD JARs,去我们工程的libs里选择libammsdk.jar,然后ok,apply就行了。2.2 AndroidManifest里添加权限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.3 注册应用到微信
你可以写在自己定义的Application里,或者是自己想要的Activity里,看自己的需要。在需要微信api的地方导入相应的类:import com.tencent.mm.sdk.openapi.WXTextObject;
2.4 微信分享
你可以弄个button之类的控件,为它设置点击事件,我这里只做文本信息的分享,其它的可以在微信开发文档上看,虽然有些难看。case R.id.weChat_friends: //构建文本信息的分享对象(其它的有WXVideoObject,WXImageObject等),内容为hello WXTextObject textObject = new WXTextObject(); textObject.text = "hello"; //将textObject分装到WXMediaMessage里 WXMediaMessage mediaMessage = new WXMediaMessage(); mediaMessage.mediaObject = textObject; mediaMessage.description = "hello"; //构建发送请求 SendMessageToWX.Req req = new SendMessageToWX.Req(); //设置发送场景为分享给微信好友 req.scene = SendMessageToWX.Req.WXSceneSession; //设置该事务为唯一事务(因为时间只有一个) req.transaction = String.valueOf(System.currentTimeMillis()); //将封装好的WXMediaMessage再封装给SendMessageToWX.Req req.message = mediaMessage; //通过IWXAPI发送请求 MyApplication.api.sendReq(req);这里面除了第一步的内容有不同,就是分享的是文本,图片,还是链接不同外,以下的步骤都差不多,那是一个微信给的流程。(MyApplication.api是我在自定义的Application里定义的:其实也就是public static IWXAPI api。)
2.5 微信登录
微信登录我觉得看文档是个很难看懂的东西......完全不知道从何入手,我百度了几天无果,通过google才算结果比较正确。2.5.1 调用微信授权窗口
同样地做一个button之类的按钮,用于跳转到微信登录界面。//微信登陆,跳转到WXEntryActivity case R.id.cjd_UnsignActivity_iv_weChat: if(!MyApplication.api.isWXAppInstalled()){ Toast.makeText(this, "请先安装微信", Toast.LENGTH_SHORT).show(); }else { SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "Moke"; MyApplication.api.sendReq(req); }做到这一步的时候,你点击就可以唤起微信登录界面了,当然我们还没有做处理结果,所以你在登录界面那里点击授权,取消什么的,它会跳转到一个空白界面而已。如果没有唤起微信登录界面,你就要检查一下开放平台上的签名正不正确啊,包名有没有写错啊,一般就是错在这些地方。
2.5.2 微信请求处理
为了处理微信请求的结果,首先我们要新建一个包,名字为“包名.wxapi”,包名就是AndroidManifest里的packagename。这个必须要遵守,然后新建一个Activity为WXEntryActivity。这里就是用于唤醒的微信登录界面,以及处理请求的地方。新建完WXEntryActivity后,要切记进行注册!! 尤其是写上android:exported="true"
<activity android:name="com.moke.wxapi.WXEntryActivity" android:exported="true" android:label="@string/app_name" ></activity>
你需要实现IWXAPIEventHandler接口,然后去重写onReq()方法和onResp()方法。另外切记要注意的,如果当你重写了这两个方法后,发现为什么点击了还是没有相关我们想要的操作的时候,你就很有可能没写:MyApplication.api.handleIntent(getIntent(), this);
接下来就是那几步操作了,你可以结合微信开发文档看看。
(1)获取code,用户点击同意授权后,会返回一个code的给你,在onResp()方法里进行。
@Override public void onResp(BaseResp arg0) { switch (arg0.errCode ) { //同意授权 case BaseResp.ErrCode.ERR_OK: SendAuth.Resp resp = (Resp) arg0; //获得code String code = resp.code; } }
在这里我们要注意这行代码 :
SendAuth.Resp resp = (Resp) arg0;
这里因为处理的是登录请求,所以我们将BaseResp强制转换为符合SenAuth,但如果你只是在onResp()方法里这样写的话,那么你的分享功能就应该会出错了,或者说可以分享成功,但返回APP的时候它会报错。因为此时你的BaseResp没有做分享信息回调的处理。
你可能会以为当时一开始做微信分享功能的时候,压根就没有用到WXEntryActivity啊,其实它是有用到的,而且当时也默认处理了你的分享回调的信息。所以我们可能会以为做分享信息只要写上发信息的代码就行了,但这只是一部分而已。
那么为了解决这个问题,你就要对BaseResp做判断了,因为你如果重新回去看微信的文档,就发现在BaseResp里有一个getType()方法,它就是显示你当前发送请求信息后返回的相应类型,那么你现在可以进入ConstantsAPI里去查看它所支持的类型有哪些。
我们可以看到这两个就是我们这里要的,一个是处理登录验证,一个是分享消息
然后点击进去后你就会看到它们相应的数值,处理登录类型的数值为1,处理分享消息类型的数值为2,所以你就要通过对它们数值的判断来作相应的处理了。
以下是我的完整的代码
package com.moke.wxapi; import java.net.URLEncoder; import org.json.JSONException; import org.json.JSONObject; import com.moke.activity.BaseActivity; import com.moke.activity.CJD_MemberCenterActivity; import com.moke.activity.CJD_UnSignActivity; import com.moke.common.PathCommonDefines; import java.net.URLEncoder; import java.util.Timer; import java.util.TimerTask; import org.json.JSONException; import org.json.JSONObject; import com.moke.common.PathCommonDefines; import com.moke.model.WeChatUser; import com.moke.until.HttpCallbackListener; import com.moke.until.HttpUtil; import com.moke.until.MyApplication; import com.tencent.mm.sdk.modelbase.BaseReq; import com.tencent.mm.sdk.modelbase.BaseResp; import com.tencent.mm.sdk.modelmsg.SendAuth; import com.tencent.mm.sdk.modelmsg.SendAuth.Resp; import com.tencent.mm.sdk.modelmsg.SendMessageToWX; import com.tencent.mm.sdk.openapi.IWXAPIEventHandler; import com.tencent.mm.sdk.openapi.WXAPIFactory; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; import android.widget.Toast; public class WXEntryActivity extends BaseActivity implements IWXAPIEventHandler { private MyApplication myApp; // 请求access_token地址格式,要替换里面的APPID,SECRET还有CODE public static String GetCodeRequest = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; // 请求unionid地址格式,要替换里面的ACCESS_TOKEN和OPENID public static String GetUnionIDRequest = "https://api.weixin.qq.com/sns/userinfo?" + "access_token=ACCESS_TOKEN&openid=OPENID"; private String newGetCodeRequest = ""; private String newGetUnionIDRequest = ""; private String mOpenId = ""; private String mAccess_token = ""; private SharedPreferences preferences; private SharedPreferences.Editor editor; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); myApp = (MyApplication) getApplication(); <span style="color:#ff0000;">myApp.api.handleIntent(getIntent(), this);</span> preferences = PreferenceManager.getDefaultSharedPreferences(this); editor = preferences.edit(); } /** * 回调微信发送的请求 */ @Override public void onReq(BaseReq arg0) { // TODO Auto-generated method stub } /** * 发送到微信请求的响应结果 * * (1)用户同意授权后得到微信返回的一个code,将code替换到请求地址GetCodeRequest里的CODE,同样替换APPID和SECRET * (2)将新地址newGetCodeRequest通过HttpClient去请求,解析返回的JSON数据 * (3)通过解析JSON得到里面的openid (用于获取用户个人信息)还有 access_token * (4)同样地,将openid和access_token替换到GetUnionIDRequest请求个人信息的地址里 * (5)将新地址newGetUnionIDRequest通过HttpClient去请求,解析返回的JSON数据 * (6)通过解析JSON得到该用户的个人信息,包括unionid */ @Override public void onResp(BaseResp arg0) { if (arg0.getType() == 2) { finish(); } if (arg0.getType() == 1) { switch (arg0.errCode) { // 同意授权 case BaseResp.ErrCode.ERR_OK: SendAuth.Resp respLogin = (Resp) arg0; // 获得code String code = respLogin.code; // 把code,APPID,APPSECRET替换到要请求的地址里,成为新的请求地址 newGetCodeRequest = getCodeRequest(code); // 请求新的地址,解析相关数据,包括openid,acces_token等 HttpUtil.sendHttpRequest(newGetCodeRequest, new HttpCallbackListener() { @Override public void onFinish(String response) { // Log.d("WXActivity", response); parseAccessTokenJSON(response); // 将解析得到的access_token和openid在请求unionid地址里替换 newGetUnionIDRequest = getUnionID(mAccess_token, mOpenId); // 请求新的unionid地址,解析出返回的unionid等数据 HttpUtil.sendHttpRequest(newGetUnionIDRequest, new HttpCallbackListener() { @Override public void onFinish(String response) { parseUnionIdJson(response); } @Override public void onError(Exception e) { } }); } @Override public void onError(Exception e) {// TODO Auto-generated method stub } }); Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() {// TODO Auto-generated method stub WXEntryActivity.this.finish(); }}; timer.schedule(task, 2000); break; // 拒绝授权 case BaseResp.ErrCode.ERR_AUTH_DENIED: finish(); break; // 取消操作 case BaseResp.ErrCode.ERR_USER_CANCEL: finish(); break; default: break; } } } /** * * 替换GetCodeRequest 将APP ID,APP SECRET,code替换到链接里 * * @param code * * 授权时,微信回调给的 * @return URL */ public static String getCodeRequest(String code) { String result = null; GetCodeRequest = GetCodeRequest.replace("APPID", urlEnodeUTF8(PathCommonDefines.WECHAT_APP_ID)); GetCodeRequest = GetCodeRequest.replace("SECRET", urlEnodeUTF8(PathCommonDefines.WECHAT_APP_SECRET)); GetCodeRequest = GetCodeRequest.replace("CODE", urlEnodeUTF8(code)); result = GetCodeRequest; return result; } /** * * 替换GetUnionID * * @param access_token * @param open_id * @return */ public static String getUnionID(String access_token, String open_id) { String result = null; GetUnionIDRequest = GetUnionIDRequest.replace("ACCESS_TOKEN", urlEnodeUTF8(access_token)); GetUnionIDRequest = GetUnionIDRequest.replace("OPENID", urlEnodeUTF8(open_id)); result = GetUnionIDRequest; return result; } public static String urlEnodeUTF8(String code) { String result = code; try { result = URLEncoder.encode(code, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return result; } /** * * 解析access_token返回的JSON数据 * * @param response */ private void parseAccessTokenJSON(String response) { // TODO Auto-generated method stubtry { JSONObject jsonObject = new JSONObject(response); mAccess_token = jsonObject.getString("access_token"); String expiresIn = jsonObject.getString("expires_in"); String refreshToken = jsonObject.getString("refresh_token"); mOpenId = jsonObject.getString("openid"); String scope = jsonObject.getString("scope"); //将获取到的数据写进SharedPreferences里 editor.putString("access_token",mAccess_token); editor.putString("expires_in",expiresIn); editor.putString("refresh_token",refreshToken); editor.putString("openid",mOpenId); editor.putString("scope", scope); editor.commit(); Log.d("WXActivity", "access_token is " + mAccess_token); Log.d("WXActivity", "expires_in is " + expiresIn); Log.d("WXActivity", "refresh_token is " + refreshToken); Log.d("WXActivity", "openid is " + mOpenId); Log.d("WXActivity", "scope is " + scope); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * * 解析unionid数据 * @param response */ private void parseUnionIdJson(String response) { try { JSONObject jsonObject = new JSONObject(response); String openid = jsonObject.getString("openid"); String nickname = jsonObject.getString("nickname"); String sex = jsonObject.getString("sex"); String province = jsonObject.getString("province"); String city = jsonObject.getString("city"); String country = jsonObject.getString("country"); String headimgurl = jsonObject.getString("headimgurl"); String unionid = jsonObject.getString("unionid"); editor.putString("nickname", nickname); editor.putString("headimgurl", headimgurl); editor.putBoolean("haveSign", true); editor.putString("unionid", unionid); editor.commit(); myApp.setWxName(nickname); Log.d("WXActivity ", " openid is " + openid); Log.d("WXActivity", "nickname is " + nickname); Log.d("WXActivity", "sex is " + sex); Log.d("WXActivity", "province is " + province); Log.d("WXActivity", "city is " + city); Log.d("WXActivity", "country is " + country); Log.d("WXActivity", "headimgurl is " + headimgurl); Log.d("WXActivity", "unionid is " + unionid); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
后面附上我用的通用网络请求
public class HttpUtil { public static void sendHttpRequest(final String address , final HttpCallbackListener listener) { new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream inputStream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder response = new StringBuilder(); String line; while((line = reader.readLine())!=null){ response.append(line); } if(listener != null){ //回调onFinish()方法 listener.onFinish(response.toString()); } } catch(Exception e){ if(listener != null){ //回调onError()方法 listener.onError(e); } }finally { if(connection != null){ connection.disconnect(); } } } }).start(); } }
回调接口:
public interface HttpCallbackListener { /** * 服务器响应成功时调用,根据返回的内容在里面处理逻辑 * @param response */ void onFinish(String response); /** * 网络操作出现错误的时候调用,在里面对异常情况进行处理 * @param e */ void onError(Exception e); }
注:以上两段代码来自郭霖老师的《第一行代码》
微信支付的参考另外一篇:Android之微信支付功能
相关文章推荐
- 社交巨头三国杀:微信、WhatsApp、Line到底有啥区别?
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件