您的位置:首页 > 移动开发 > 微信开发

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

2015-11-07 15:36 731 查看
最近在做一个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等),内容为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之微信支付功能
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息