Android之微信接入分享,登录功能。

来源:互联网 发布:坐久了腰疼 知乎 编辑:程序博客网 时间:2024/05/28 20:20

最近在做一个APP项目,需要用到微信分享啊,登录这些。

微信支付的参考另外一篇: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等),内容为helloWXTextObject 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之类的按钮,用于跳转到微信登录界面。
//微信登陆,跳转到WXEntryActivitycase 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()方法里进行。

@Overridepublic void onResp(BaseResp arg0) {switch (arg0.errCode ) {//同意授权case BaseResp.ErrCode.ERR_OK:SendAuth.Resp resp = (Resp) arg0;//获得codeString 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还有CODEpublic 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和OPENIDpublic 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;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);myApp = (MyApplication) getApplication();<span style="color:#ff0000;">myApp.api.handleIntent(getIntent(), this);</span>preferences = PreferenceManager.getDefaultSharedPreferences(this);editor = preferences.edit();}/** * 回调微信发送的请求 */@Overridepublic 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 */@Overridepublic 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;// 获得codeString code = respLogin.code;                        // 把code,APPID,APPSECRET替换到要请求的地址里,成为新的请求地址newGetCodeRequest = getCodeRequest(code);// 请求新的地址,解析相关数据,包括openid,acces_token等HttpUtil.sendHttpRequest(newGetCodeRequest, new HttpCallbackListener() {@Overridepublic 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() {@Overridepublic void onFinish(String response) {parseUnionIdJson(response);}@Overridepublic void onError(Exception e) {}});}@Overridepublic void onError(Exception e) {// TODO Auto-generated method stub}});Timer timer = new Timer();TimerTask task = new TimerTask() {@Overridepublic void run() {// TODO Auto-generated method stubWXEntryActivity.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 blocke.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 blocke.printStackTrace();}}}


后面附上我用的通用网络请求
public class HttpUtil {public static void sendHttpRequest(final String address , final HttpCallbackListener listener) {new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubHttpURLConnection 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之微信支付功能




0 0
原创粉丝点击