由于公司的需求,app需要使用微信登录以及分享到微信等功能,近期对微信的第三方登录、分享功能进行了少许研究,并记录如下。
注意点:
1、 需到“微信开放平台”进行注册;
2、 注册完后如果未进行“开发者资质认证“,微信开放平台帐号下的应用,只能拥有分享给朋友或者发送到朋友圈两个功能的权限。
3、 “开发者资质认证“通过后,微信开放平台帐号下的应用,将获得微信登录、智能接口、公众号第三方平台开发等高级能力。
4、 “开发者资质认证“的有效期为1年,有效期最后两个月可申请年审即可续期,审核费用为300元。
成功注册并登陆微信公众平台后可以看到如上页面,我们目前开发用的基本是“资源中心“,”管理中心“。
注意在创建应用的时候我们不可以在应用的名字中包含“微信“等字样,我就是因为第一次写名称使用了”微信SDK测试“,结果审核不给通过。
这里重要的就是应用的签名,关于签名的获取,我们需要先给自己的应用签名,无论你是使用Eclipse还是Android Studio开发都需要先给你自己的应用签名打包成Apk然后安装到手机上,然后使用微信资源中心提供的签名生成apk,安装到手机上。在手机上打开签名生成工具输入你应用的包名即可得到你应用的签名。
以下地址是微信资源中心签名工具的地址:
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=75dc8457c70c2f4324e9cfd255674d7965d65049&lang=zh_CN
填写完整并提交完毕后就需要耐心等待审核通过了,一般半天就会有结果的。审核通过后可以查看应用的信息如下,这里重要的就是应用的AppID与AppSecret,接下来集成SDK的时候要用到这两个值。
1) 申请到的AppID。
2) 微信SDK,在资源中心—资源下载—Andoid资源下载中即可下载。微信SDK连接如下:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&lang=zh_CN
下载完毕解压后里面最重要的文件就是libammsdk.jar这个jar包了,其他暂时不需要。
在工程中新建一个libs目录,将开发工具包中libs目录下的libammsdk.jar复制到该目录中.
右键单击工程,选择Build Path中的Configure Build Path…,选中Libraries这个tab,并通过Add Jars…导入工程libs目录下的libammsdk.jar文件。(如下图所示)
将工程切换到Project视图,然后将开发工具包中libs目录下的libammsdk.jar复制到该工程的app→libs目录中。
右键刚刚粘贴进来的libammsdk.jar文件,在弹出的菜单上点击Add As Library即可,如下图所示。
Jar包在导入的时候针对两种开发工具写了Eclipse和Android Studio两种导入方法,导入完毕后进行代码的开发时则不用区分不同开发工具的用法了。
这一步比较简单不会涉及太多的东西。微信分享及收藏目前支持文字、图片、音乐、视频、网页共五种类型。
但是要使你的程序启动后微信终端能响应你的程序,必须在代码中向微信终端注册你的APPID。这一步的原理就相当于:你想联系一个人,那么你就必须先给他打个电话,电话接通了你们才能通话,否则则无法联系。所以这个“打电话”的过程是需要在你要分享之前执行的,你可以在Application中注册,也可以在一个Activity中注册,注意只需要注册一次就好了。其他时候也需要使用IWXAPI,但是不需要再注册了。
注册代码类似如下:
private static final String WECHAT_APP_ID = "你申请应用得到的APPID";
// IWXAPI是第三方app和微信通信的openapi接口
private IWXAPI iwxapi;
/**
* 将当前应用的APP_ID注册到微信
*/
private void regToWx() {
iwxapi = WXAPIFactory.createWXAPI(this,WECHAT_APP_ID, true);
iwxapi.registerApp(WECHAT_APP_ID);
}
分享或收藏的目标场景,通过修改scene场景值实现(下文中红色代码处为修改分享的场景)。
发送到聊天界面——WXSceneSession
发送到朋友圈——WXSceneTimeline
添加到微信收藏——WXSceneFavorite
具体的分享的用法如下,在调用封装好的方法之前别忘了下面的两句代码。
private IWXAPI api;
api = WXAPIFactory.createWXAPI(this,WECHAT_APP_ID, true);
(以下代码中做了封装,与官网中开发文档中不符的以官方文档为主)
/**
* 分享到微信
*
* @param text 文字内容
* @param isShareToTimeline false表示分享给朋友,true表示分享到朋友圈
*/
public static void sendReqText(String text, boolean isShareToTimeline) {
// 初始化一个WXTextObject对象
WXTextObject textObj = new WXTextObject();
textObj.text = text;
// 用WXTextObject对象初始化一个WXMediaMessage对象
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = textObj;
// 发送文本类型的消息时,title字段不起作用
// msg.title = "Will be ignored";
msg.description = text;
// 构造一个Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("text"); // transaction字段用于唯一标识一个请求
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
// 调用api接口发送数据到微信
api.sendReq(req);
}
(以下代码中做了封装,与官网中开发文档中不符的以官方文档为主)
/**
* 发送图片到微信
*
* @param context 上下文
* @param index 索引。0:表示Bitmap文件;1:表示手机本地图片;2:表示网络图片(图片的URL)
* @param isShareToTimeline false表示分享给朋友,true表示分享到朋友圈
*/
public static void sendReqImg(Context context, int index, boolean isShareToTimeline) {
switch (index) {
case 0: {
Bitmap bmp = BitmapFactory.decodeResource(context.getResources(), R.mipmap.welcome);
WXImageObject imgObj = new WXImageObject(bmp);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true); // 设置缩略图
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
case 1: {
String path = SDCARD_ROOT + "/test.png";
File file = new File(path);
if (!file.exists()) {
String tip = "图片文件不存在";
Toast.makeText(context, tip + " path = " + path, Toast.LENGTH_LONG).show();
break;
}
WXImageObject imgObj = new WXImageObject();
imgObj.setImagePath(path);
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
Bitmap bmp = BitmapFactory.decodeFile(path);
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
case 2: {
String url = "http://weixin.qq.com/zh_CN/htmledition/images/weixin/weixin_logo0d1938.png";
try {
WXImageObject imgObj = new WXImageObject();
imgObj.imageUrl = url;
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = imgObj;
Bitmap bmp = BitmapFactory.decodeStream(new URL(url).openStream());
Bitmap thumbBmp = Bitmap.createScaledBitmap(bmp, THUMB_SIZE, THUMB_SIZE, true);
bmp.recycle();
msg.thumbData = Util.bmpToByteArray(thumbBmp, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("img");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
default:
break;
}
}
(以下代码中做了封装,与官网中开发文档中不符的以官方文档为主)
/**
* 分享音乐到微信
*
* @param context 上下文
* @param index 索引。0:表示发送音乐url;1表示发送低带宽音乐url
* @param musicUrl 音乐的URL
* @param title 标题
* @param description 描述
* @param isShareToTimeline false表示分享给朋友,true表示分享到朋友圈
*/
public static void sendReqMusic(Context context, int index, String musicUrl, String title, String description, boolean isShareToTimeline) {
switch (index) {
case 0: {
WXMusicObject music = new WXMusicObject();
music.musicUrl = musicUrl;
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = music;
msg.title = title;
msg.description = description;
Bitmap thumb = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
msg.thumbData = Util.bmpToByteArray(thumb, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("music");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
case 1: {
WXMusicObject music = new WXMusicObject();
music.musicLowBandUrl = musicUrl;
WXMediaMessage msg = new WXMediaMessage();
msg.mediaObject = music;
msg.title = title;
msg.description = description;
Bitmap thumb = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
msg.thumbData = Util.bmpToByteArray(thumb, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("music");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
default:
break;
}
}
(以下代码中做了封装,与官网中开发文档中不符的以官方文档为主)
/**
* 分享视频到微信
*
* @param context 上下文
* @param index 索引。0:表示发送视频url;1:表示发送低带宽视频url
* @param title 标题
* @param description 描述
* @param isShareToTimeline false表示分享给朋友,true表示分享到朋友圈
*/
public static void sendReqVideo(Context context, int index, String VideoUrl, String title, String description, boolean isShareToTimeline) {
switch (index) {
case 0: {
WXVideoObject video = new WXVideoObject();
video.videoUrl = VideoUrl;
WXMediaMessage msg = new WXMediaMessage(video);
msg.title = title;
msg.description = description;
Bitmap thumb = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
msg.thumbData = Util.bmpToByteArray(thumb, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("video");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
case 1: {
WXVideoObject video = new WXVideoObject();
video.videoLowBandUrl = VideoUrl;
WXMediaMessage msg = new WXMediaMessage(video);
msg.title = title;
msg.description = description;
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("video");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
break;
}
default:
break;
}
}
(以下代码中做了封装,与官网中开发文档中不符的以官方文档为主)
/**
* 分享网址到微信
*
* @param context 上下文
* @param webUrl 要分享的网址
* @param title 标题
* @param description 描述
* @param isShareToTimeline false表示分享给朋友,true表示分享到朋友圈
*/
public static void sendReqWeb(Context context, String webUrl, String title, String description, boolean isShareToTimeline) {
WXWebpageObject webpage = new WXWebpageObject();
webpage.webpageUrl = webUrl;
WXMediaMessage msg = new WXMediaMessage(webpage);
msg.title = title;
msg.description = description;
Bitmap thumb = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher);
msg.thumbData = Util.bmpToByteArray(thumb, true);
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction("webpage");
req.message = msg;
//要分享给好友还是分享到朋友圈
req.scene = isShareToTimeline ? SendMessageToWX.Req.WXSceneTimeline : SendMessageToWX.Req.WXSceneSession;
api.sendReq(req);
}
这样只要正确调用了上面的方法基本也就分享成功了,但是这里并不完善,因为分享完毕返回我们的app时微信还会返回给我们的app一些数据,来表示分享成功、失败或者取消的状态。但是这并不影响app的使用,具体的回调函数我们在下文中再做详解。
使用微信登录会有三种情况:
1、 用户手机上没有微信,那么就提示没有微信,并引导用户下载(官方说法);
2、 用户手机上有微信,但是没有登录,那么需要用户使用账号密码登录;
3、 用户手机上有微信,并且已登录,那么只需要用户点击授权按钮即可;
这里会涉及到许多东西,我们先大概看一下整个请求微信登陆的过程。(这里也是我根据官方的文档然后自己的理解来的,如有错误纰漏之处还请指出)
注: 实线代表客户端请求客户端或者服务端
虚线代表服务端相应客户端的请求
0、 首先,用户偷懒不想注册想使用微信的账号密码登录(额,好吧);
1、 用户在app中点击“微信登录”按钮,我们的app这时需要请求微信;
2、 集成好的app去调用微信,微信给出相应(开始提到的三种情况);
3、 用户下载好后,登录后者直接授权后,提交结果给微信服务器;
4、 微信服务器根据结果返回临时code(新版的jar包中返回的code名称改为了token,但实际仍为code的值,使用方法一致);
5、 App根据临时的code、AppID以及AppSecret换取微信的access_token。一同返回的还有refresh_token,因为access_token是有有效期的,过期后可以使用refresh_token进行刷新。但是refresh_token也是有有效期的,一般是30天,这个过期了就需要用户重新进行授权了;
6、 微信服务器响应,返回access_token等信息;
7、 根据得到的access_token可以拿到用户的基本信息,如下:
到此,微信登录也就明朗了,代码就不必贴了吧,请参考微信的官方文档,剩下文章稍后完善。