android 同时实现微信分享和微信登录功能

    Android应用实现微信登录与分享


    1. 闲话(可直接无视

    项目慢慢的推进,逐渐的做到了微信第三方登录的功能模块了。其实我想说Orz,我等这一天等了好久了,想做个微信验证登录都等了两个多星期咧(其实是我们这边出了点问题),先要申请微信开放平台的帐号,在里面创建一个应用,通过审核之后再交300软妹币,是的,你没有听错,上交300软妹币(听说会成为传说中的认证开发者)才可以获得应用第三方登录的权限,否则只能够分享到盆友圈。中间也是遇到了一些小问题,微信那边的文档写的也不是特别的清楚,还有一些关于微信分享到朋友圈和好友方面的,下面就把问题和解决方法给大家呈上来。


    2. 概述

    在之前只有微信分享的功能,到后来慢慢的发展出了微信登录的模块,分享的功能比较好做,按照微信给的文档构造好需要传递的信息,再调用微信分享接口,即可跳转至微信的页面进行分享了。登录的功能比分享稍微复杂,需要和微信服务器进行至少三次的数据交换(第一步获取code, 第二步通过code获取access_token以及其他的凭证, 第三步再通过access_token来调用微信的接口)。


    3. 正文

    3.1 appId申请

    如需帐号申请,请跟随链接移步,注册一个帐号后在管理中心—>移动应用找到创建移动应用。 

    进入后在里面填写各种需要的信息,要注意的是这里的应用审核通过后,应用名称不允许修改,所以各位给自己心爱的应用选一个好听的名字咯(貌似都被注册光了)。 

    下一步后,会看到要填写应用官网,应用下载地址,应用签名,应用包名等资料。

    应用包名就是项目文件AndroidManifest.xml文件里面的package="com.ldx.microtravelnotes"这个东西。获取应用签名需要先在手机上面安装好应用的release签名版app,再安装一个微信提供的签名生成工具,这个工具安装在手机上后,输入app的应用包名,即可生成应用签名,填写后提交给微信,等待审核的通过。 

    通过审核之后,会得到微信分配给申请app的appId和appSecret,以及一些能够免费使用的权限(例如分享至微信朋友圈等),如果需要微信验证登录,则要上交300软妹币,成为传说中的验证开发者才可以使用。


    在开始做登录和分享之前,还需要下载微信提供的SDK开发包,将这个包导入到项目的libs文件夹里面,再add as library就可以正常的使用了。还需要注意的一点就是要在AndroidManifest.xml文件里面加入如下的权限:

<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"/> 

    3.2 微信分享

    既然微信登录那边还需要再次验证开发者,我们就先来说说微信分享的实现步骤吧,其实小达在做分享的时候还是挺顺利的(相对于登录来说)。实现微信分享功能分为以下几个步骤:

第一步

利用appId(注册后会得到)将app注册到微信
public static IWXAPI api;
  private void registerToWx() {
    api = WXAPIFactory.createWXAPI(this, AppConstant.APP_ID, false);
    api.registerApp(AppConstant.APP_ID);
  }

    上面的AppConstant.APP_ID即字符串常量,也就是申请得到的appId,将这些代码放在应用启动时候的Activity或者Application类里面,onCreate()方法调用的时候,顺带的调用registerToWx(),小达这边是有一个在app启动时候绑定的一个Application类,放在了onCreate()里面,贴上一小部分代码,

AndroidManifest.xml
<application
        android:name=".global.MTNApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
public class MTNApplication extends CommonApplication {
  public static IWXAPI api;
  private void registerToWx() {
    api = WXAPIFactory.createWXAPI(this, AppConstant.APP_ID, false);
    api.registerApp(AppConstant.APP_ID);
  }

  @Override
  public void onCreate() {
    super.onCreate();
    registerToWx();
  }
 }

    当然也可以写在Activity的onCreate()方法里面,个人觉得放在欢迎页面里面也不错哦。

第二步

在需要分享的位置编写如下代码

private void shareArticleToWx(final int flag) {
    if (!MTNApplication.api.isWXAppInstalled()) {
      AppData.showToast("您还未安装微信客户端");
      return;
    }
    WXWebpageObject webPage = new WXWebpageObject();
    webPage.webpageUrl = ArticleApi.getDisplayArticleUrl(mArticleId, mArticleTemp);
    WXMediaMessage msg = new WXMediaMessage(webPage);
    msg.title = "笔记";
    msg.description = mArticleTitle;
    msg.setThumbImage(loadedImage);
    SendMessageToWX.Req req = new SendMessageToWX.Req();
    req.transaction = String.valueOf(System.currentTimeMillis());
    req.message = msg;
    req.scene = flag == 0 ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline;
    MTNApplication.api.sendReq(req);
  }

    上面的代码也就是按照微信给的结构,构造了一个微信分享信息,在这个微信分享信息中,可以设置点击跳转的url,这条分享信息的标题等,其中有一个flag参数,这个参数是用来确定分享给朋友圈(flag == 1)还是分享给好友(flag == 0)的。最后通过一个已经注册过的IWXAPI类的实例来发送出分享请求。

第三步

创建一个供微信调用的Activity

    创建这个Activity的位置不能随便放,需要在包名下面创建一个新的文件夹 wxapi,再在这个文件夹下创建 WXEntryActivity.java文件。项目的结构如图,一定不要放错了,因为微信可能无法调用: 
 
创建完成之后还需要在 AndroidManifest.xml文件中对WXEntryActivity进行设置: android:exported="true"

    创建的WXEntryActivity.java继承自Activity,实现IWXAPIEventHandler接口,该接口即处理微信和app通信的不同event:

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

  //这两个参数在文档中没有找到,可能是瞎了,,,自己在代码里面找了会才找到,这两个常量代表了微信返回的消息类型,是对登录的处理还是对分享的处理,登录会在后面介绍到
  private static final int RETURN_MSG_TYPE_LOGIN = 1;
  private static final int RETURN_MSG_TYPE_SHARE = 2;

  private static final String TAG = "WXEntryActivity";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wxentry);

    //如果没回调onResp,八成是这句没有写
    MTNApplication.api.handleIntent(getIntent(), this);
  }


  //微信发送消息给app,app接受并处理的回调函数
  @Override
  public void onReq(BaseReq baseReq) {

  }

  //app发送消息给微信,微信返回的消息回调函数,根据不同的返回码来判断操作是否成功
  @Override
  public void onResp(BaseResp resp) {
    switch (resp.errCode) {
      case BaseResp.ErrCode.ERR_AUTH_DENIED:
      case BaseResp.ErrCode.ERR_USER_CANCEL:
        showToast("微信失败");
        break;

      case BaseResp.ErrCode.ERR_OK:
        switch (resp.getType()) {
          case RETURN_MSG_TYPE_SHARE:
            showToast("微信分享成功");
            finish();
            break;
        }
        break;
    }
  }
 }

    微信分享到这里就做完了,需要上面的三个步骤即可实现,需要注意的是第二步构造分享信息,以及第三步在设置微信回调页面的时候。

    3.3 微信登录

    在上面微信分享的基础上,再来做微信登录的功能。微信登录前的准备工作和微信分享一样,先将app注册到微信端,app也是通过WXEntryActivity来处理返回的消息。分下面几个步骤进行:

第一步

注册app到微信

    这一步的工作和前面是一样的,如果这个已经完成了,直接跳到下一步。

第二步

发送code请求到微信

    在需要微信登录的地方添加上一个按钮,用来点击后调用微信登录页面。之前开始不知道微信验证登录的界面是什么情况,还以为要自己写好,其实是微信那边已经写好了的界面(并非我们的WXEntryActivity),我们只需要在自己的app这边发送请求就会自动跳转到微信的页面。发送code请求的代码如下:

 if (!MTNApplication.api.isWXAppInstalled()) {
      AppData.showToast("您还未安装微信客户端");
      return;
 }
 final SendAuth.Req req = new SendAuth.Req();
 req.scope = "snsapi_userinfo";
 req.state = "diandi_wx_login";
 MTNApplication.api.sendReq(req);

    上面构造并通过注册好了的api发送了一个请求,请求中scope是固定的形式,用来请求微信验证登录,官方解释:

授权作用域(scope)代表用户授权给第三方的接口权限,第三方应用需要向微信开放平台申请使用相应scope的权限后,使用文档所述方式让用户进行授权,经过用户授权,获取到相应access_token后方可对接口进行调用。如获取用户个人信息则填写snsapi_userinfo

    参数state是可以自定义的,官方解释:

用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

    效果大概是这样的: 
    这个页面就是WXEntryActivity,上面加了一个按钮,用来点击之后执行上面的那一段代码, 

    点击之后,向微信发送了请求,会自动跳转到微信的界面,也就是下面的这张图片,这个界面是微信已经写好了的,我们就不用操心了。 

    小达实验了一下,先开始将这个微信验证登录的按钮放在了WXEntryActivity.java中,点击了微信界面登录之后会返回到WXEntryActivity界面中去,后来又想了下,如果不放在WXEnrtyActivity中会怎么样,于是另外写了一个Activity专门用来登录,结果是从微信确认登录之后又返回了WXEnrtyActivity,所以个人认为还是直接放在WXEnrtyActivity里面比较好。反正去了总是要回到这个界面进行处理的。

第三步

利用微信返回的code去请求access_token

    第二步拿到的code还不算完呢,这个code的声明周期只有五分钟,而且每个code只可以用一次,切记请勿重复使用,否则就会出现 {"errcode":40029,"errmsg":"invalid code"}这种问题了。也是构造一个请求发送给微信,可以直接接在获取code之后,立马把这个请求发送出去,因为是属于微信登录的中间操作。通过code请求access_token的接口如下:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

参数说明

参数必须说明
appid应用唯一标识,在微信开放平台提交应用审核通过后获得
secret应用密钥AppSecret,在微信开放平台提交应用审核通过后获得
code填写第一步获取的code参数
grant_type填authorization_code

    问我在那里获取微信返回的code?肯定是在WXEntryActivity里面咯,前面提到了这个activity是专门用来给微信调用的,附上WXEnrtyActivity.java里面的代码:

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

  private Button checkLogin;

  private static final int RETURN_MSG_TYPE_LOGIN = 1;
  private static final int RETURN_MSG_TYPE_SHARE = 2;

  private static final String TAG = "WXEntryActivity";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wxentry);
    checkLogin = (Button) findViewById(R.id.check_login);
    checkLogin.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if (!MTNApplication.api.isWXAppInstalled()) {
          AppData.showToast("您还未安装微信客户端");
          return;
        }
        final SendAuth.Req req = new SendAuth.Req();
        req.scope = "snsapi_userinfo";
        req.state = "diandi_wx_login";
        MTNApplication.api.sendReq(req);
      }
    });

    //如果没回调onResp,八成是这句没有写
    MTNApplication.api.handleIntent(getIntent(), this);
  }


  //微信直接发送给app的消息处理回调
  @Override
  public void onReq(BaseReq baseReq) {

  }

  //app发送消息给微信,处理返回消息的回调
  @Override
  public void onResp(BaseResp resp) {
    switch (resp.errCode) {

      case BaseResp.ErrCode.ERR_AUTH_DENIED:
      case BaseResp.ErrCode.ERR_USER_CANCEL:
        if (RETURN_MSG_TYPE_SHARE == resp.getType()) AppData.showToast("分享失败");
        else AppData.showToast("登录失败");
        break;
      case BaseResp.ErrCode.ERR_OK:
        switch (resp.getType()) {
          case RETURN_MSG_TYPE_LOGIN:
          //拿到了微信返回的code,立马再去请求access_token
            String code = ((SendAuth.Resp) resp).code;

            //就在这个地方,用网络库什么的或者自己封的网络api,发请求去咯,注意是get请求

            break;

          case RETURN_MSG_TYPE_SHARE:
            AppData.showToast("微信分享成功");
            finish();
            break;
        }
        break;
    }
  }
}

    请求返回回来的参数形式如下:

{ 
"access_token":"ACCESS_TOKEN", 
"expires_in":7200, 
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID", 
"scope":"SCOPE",
"unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

官方给出的参数列表:

参数说明
access_token微信接口调用凭证
expires_inaccess_token接口调用凭证超时时间,单位(秒)
refresh_token用户刷新access_token
openid授权用户唯一标识
scope用户授权的作用域,使用逗号(,)分隔
unionid只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。

    微信验证登录到这里就差不多了,验证的主要目的就是拿到微信给的这个access_token,用来调用微信的各种接口,可以获取用户的基本信息等等。下面就来说说在做的过程中遇到了那些坑的地方(其实就是在自己坑自己Orz)。

    4. 填坑环节

    在做微信登录模块的时候,遇到了一些小的问题如下,现在给出一些小的建议:

  1. 请求登录,没有回调,可能是由于WXEntryActivity的onCreate()方法里面没有处理intent。 MTNApplication.api.handleIntent(getIntent(), this);
  2. 获取到code之后,一个code的寿命只有5分钟,而且只能用一次,如果重复利用就会出现{“errcode”:40029,”errmsg”:”invalid code”}的情况。
  3. 应用签名:XXXXX 包名:com.X.X这两个一定不能写反咯,写反就死翘翘了,写反了也会{“errcode”:40029,”errmsg”:”invalid code”}。
  4. 拿到code后,如果需要通过自己的服务器向微信发送获取access_token的请求,也要注意code只能用一次(当然不算你给自己服务器的那次),如果你们后台还承担着微信公众号的事务,则要小心不要将微信公众号的appid和app_secret与微信开放平台上的弄混了,否则也会返回{“errcode”:40029,”errmsg”:”invalid code”}。

    以上就是对微信登录以及分享的一些小心得,拿出来和大家分享一下,有什么错误的地方还望多多指教。

发表评论

查看评论
  • 1楼u0130662922015-11-19 10:33

    我想问一下,那我要弄个按钮退出登录的话这个怎么写?

更多评论(1)
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值