/*
* 微信第三方 此类必须存在,必须在“****.wxapi”包中
*/
public class WXEntryActivity extends AppCompatActivity implements IWXAPIEventHandler {
// IWXAPI 是第三方app和微信通信的openapi接口
public static WXEntryActivity wx_instance;
private IWXAPI api;
private static final String TAG = "YLWANG_WX";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wx_instance = WXEntryActivity.this;
api = WXAPIFactory.createWXAPI(this, WX_APP_ID, false);
api.registerApp(WX_APP_ID);
api.handleIntent(getIntent(), this);
}
// 微信发送请求到第三方应用时,会回调到该方法
@Override
public void onReq(BaseReq arg0) {
}
// 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
@Override
public void onResp(BaseResp resp) {
if (resp.getType() == ConstantsAPI.COMMAND_SENDAUTH) {//如果是登录回调
Logs.d(TAG, "onResp" + "方法被执行2错误码 = " + resp.errCode);
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK://登录成功
if (resp instanceof SendAuth.Resp) {
SendAuth.Resp newResp = (SendAuth.Resp) resp;
//获取微信传回的code
String code = newResp.code;
getWXOpenId(code);
}
break;
case BaseResp.ErrCode.ERR_USER_CANCEL: // 登录取消
Utils.showToast(getApplicationContext(), "登录取消");
Logs.d(TAG, "ERR_USER_CANCEL");
this.finish();
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
// 登录拒绝
Utils.showToast(getApplicationContext(), "登录拒绝");
Logs.d(TAG, "ERR_AUTH_DENIED");
this.finish();
break;
}
//如果是分享回调
} else if (resp.getType() == ConstantsAPI.COMMAND_SENDMESSAGE_TO_WX) {
switch (resp.errCode) {
case BaseResp.ErrCode.ERR_OK:
Utils.showToast(getApplicationContext(), "分享成功");
this.finish();
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
Utils.showToast(getApplicationContext(), "操作取消");
this.finish();
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
Utils.showToast(getApplicationContext(), "分享拒绝");
this.finish();
break;
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i(TAG, "onNewIntent");
setIntent(intent);
api.handleIntent(intent, this);
}
public static final String WX_URL_1 = "https://api.weixin.qq.com/sns/oauth2/access_token";
public static final String WX_URL_2 = "https://api.weixin.qq.com/sns/userinfo";
/**
* 获取openid accessToken值用于后期操作
*
* @param code 请求码
*/
public void getWXOpenId(final String code) {
//WX_URL_1 = "https://api.weixin.qq.com/sns/oauth2/access_token";
OkGoUtils.postByOkGo(WXOpenIdBean.class, WX_URL_1, new SKMapCallBack() {
@Override
public Map<String, String> getParams() {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", WX_APP_ID);
map.put("secret", WX_APP_SECRET);
map.put("code", code);
map.put("grant_type", "authorization_code");
return map;
}
}, new BeanCallBack() {
@Override
public void onSuccess(Object t) {
WXOpenIdBean wxOpenIdBean = (WXOpenIdBean) t;
String openId = wxOpenIdBean.getOpenid();
String accessToken = wxOpenIdBean.getAccess_token();
//拿到openId之后再获取用户信息,如昵称,头像,性别,城市等
getUserInfo(openId, accessToken);
}
});
}
/**
* 获取用户唯一标识
*
* @param openId
* @param accessToken
*/
private void getUserInfo(final String openId, final String accessToken) {
//WX_URL_2 = "https://api.weixin.qq.com/sns/userinfo";
OkGoUtils.postByOkGo(WXUserInfoBean.class, WX_URL_2, new SKMapCallBack() {
@Override
public Map<String, String> getParams() {
Map<String, String> map = new HashMap<String, String>();
map.put("access_token", accessToken);
map.put("openid", openId);
return map;
}
}, new BeanCallBack() {
@Override
public void onSuccess(Object t) {
WXUserInfoBean wxUserInfoBean = (WXUserInfoBean) t;
String nickName = wxUserInfoBean.getNickname();
String headUrl = wxUserInfoBean.getHeadimgurl();
//TODO:此处根据openId和nickName执行登录
Utils.showToast(WXEntryActivity.this, "微信授权登录成功");
LoginManager.loginByOAuth(WX, openId, nickName, headUrl, new SKStringCallBack() {
@Override
public void getResult(String result) {
if ("OK".equals(result)) {
startActivity(new Intent(WXEntryActivity.this, UserActivity.class));
WXEntryActivity.this.finish();
}
}
});
}
});
}
}
其中Bean类有
/**
* Created by ylwang on 2017/8/2.
*/
public class WXOpenIdBean {
/**
* access_token : JytUQhfBmQ7uQVsg123456788jKEggcGeL13T7Kvn80LOWqdLjVlT5LG6-rrxXY
* refresh_token : PsxBur8TtJXMaAJH83l12345678dOHooM4ve0EErZpvr2EX21QCl6kIggrc
* unionid : oScohwfwq16_1ZkJccExjtqF3SlY
* openid : oyNmX01234567M7REk8
* scope : snsapi_userinfo
* expires_in : 7200
*/
private String access_token;
private String refresh_token;
private String unionid;
private String openid;
private String scope;
private int expires_in;
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public void setScope(String scope) {
this.scope = scope;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
}
public String getAccess_token() {
return access_token;
}
public String getRefresh_token() {
return refresh_token;
}
public String getUnionid() {
return unionid;
}
public String getOpenid() {
return openid;
}
public String getScope() {
return scope;
}
public int getExpires_in() {
return expires_in;
}
}
/**
* Created by ylwang on 2017/8/2.
*/
public class WXUserInfoBean {
/**
* country : CN
* unionid : oScohw123456Jcc12345678F3SlY
* province :
* city :
* openid : oyNmX1234LU5dM124k12348
* sex : 1
* nickname : iblade
* headimgurl : http://wx.qlogo.cn/mmopen/JSA123456tdYH123456f3x/0
* language : zh_CN
*/
private String country;
private String unionid;
private String province;
private String city;
private String openid;
private int sex;
private String nickname;
private String headimgurl;
private String language;
public void setCountry(String country) {
this.country = country;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
public void setProvince(String province) {
this.province = province;
}
public void setCity(String city) {
this.city = city;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public void setSex(int sex) {
this.sex = sex;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCountry() {
return country;
}
public String getUnionid() {
return unionid;
}
public String getProvince() {
return province;
}
public String getCity() {
return city;
}
public String getOpenid() {
return openid;
}
public int getSex() {
return sex;
}
public String getNickname() {
return nickname;
}
public String getHeadimgurl() {
return headimgurl;
}
public String getLanguage() {
return language;
}
}
//TODO:第三方登录相关
private Tencent mTencent;
private UserInfo mInfo;
private IUiListener loginListener;
public static final String PACKAGE_QQ = "com.tencent.mobileqq";
public static final String PACKAGE_WECHAT = "com.tencent.mm";
/**
* 初始化第三方登录相关
*/
private void initOAuth() {
mTencent = Tencent.createInstance(QQ_APP_ID, getApplicationContext());
}
private void loginByQQ() {
if (!isAuthClientAvailable(mActivity, PACKAGE_QQ)) {
Utils.showToast(this, "您尚未安装QQ,请先下载安装");
return;
}
if (!mTencent.isSessionValid()) {
loginListener = new BaseUiListener() {
@Override
protected void doComplete(JSONObject values) {
updateUserInfo();
}
};
mTencent.login(this, "all", loginListener);
} else {
mTencent.logout(this);
updateUserInfo();
}
}
private void updateUserInfo() {
// ContextUtil.dismissDialog(mActivity);
if (mTencent != null && mTencent.isSessionValid()) {
IUiListener infoListener = new IUiListener() {
@Override
public void onError(UiError e) {
}
@Override
public void onComplete(final Object response) {
Message msg = Message.obtain();
msg.obj = response;
msg.what = QQ_USER_INFO;
handler.sendMessage(msg);
}
@Override
public void onCancel() {
}
};
mInfo = new UserInfo(this, mTencent.getQQToken());
mInfo.getUserInfo(infoListener);
}
}
public static final int QQ_USER_INFO = 3;
private String QQ_openID;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case QQ_USER_INFO:
JSONObject response = (JSONObject) msg.obj;
if (response.has("nickname") && !TextUtils.isEmpty(QQ_openID)) {
try {
String nick_name = response.getString("nickname");
String head_img_url = response.getString("figureurl_qq_2");
//TODO:执行QQ登录
LoginManager.loginByOAuth(QQ, QQ_openID, nick_name, head_img_url, new SKStringCallBack() {
@Override
public void getResult(String result) {
if ("OK".equals(result)) {
startActivity(new Intent(LoginActivity.this, UserActivity.class));
LoginActivity.this.finish();
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
};
private class BaseUiListener implements IUiListener {
@Override
public void onComplete(Object response) {
try {
Gson gson = new Gson();
QQOpenIdBean qqOpenIdBean = gson.fromJson(String.valueOf(response), QQOpenIdBean.class);
QQ_openID = qqOpenIdBean.getOpenid();
String accessToken = qqOpenIdBean.getAccess_token();
String expires = qqOpenIdBean.getExpires_in() + "";
mTencent.setOpenId(QQ_openID);
mTencent.setAccessToken(accessToken, expires);
Logs.d("+++", "onComplete: " + response.toString());
} catch (Exception e) {
e.printStackTrace();
}
doComplete((JSONObject) response);
}
protected void doComplete(JSONObject values) {
}
@Override
public void onError(UiError e) {
Logs.d("+++", "onError: " + e.errorDetail);
}
@Override
public void onCancel() {
Logs.d("+++", "onCancel: ");
}
}
/**
* 微信登陆 申请授权
*/
private SendAuth.Req req;
private IWXAPI api;
private static final String WEIXIN_SCOPE = "snsapi_userinfo";// 用于请求用户信息的作用域
private static final String WEIXIN_STATE = "login_state"; // 自定义
private static final String TAG_WECHAT = "WECHAT";
private void loginByWeChat() {
if (!isAuthClientAvailable(mActivity, PACKAGE_WECHAT)) {
Utils.showToast(this, "您尚未安装微信,请先下载安装");
return;
}
// ContextUtil.showDialog(mActivity, "正在获取信息……");
if (api == null) {
api = WXAPIFactory.createWXAPI(LoginActivity.this, WX_APP_ID);
api.registerApp(WX_APP_ID);
}
req = new SendAuth.Req();
//授权读取用户信息
req.scope = WEIXIN_SCOPE;
//自定义信息
req.state = WEIXIN_STATE;
//向微信发送请求
boolean isEnableOAuth = api.sendReq(req);
// LoginActivity.this.finish();//跳转到微信界面后销毁登录界面
Log.d("```", "向微信发送请求后,是否拉起成功:" + isEnableOAuth);
/**api.sendReq(req)返回true:拉起成功,跳到微信授权页面
false:拉起失败,要提示用户。当手机未安装微信客户端时,会拉起失败*/
}
其中用部分工具类代码如下:
/**
* Created by ylwang on 2017/7/17.
*/
public class Utils {
/**
* 获得屏幕宽度
*
* @return
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获得屏幕高度
*
* @return
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
public static int getDpi(Context context) {
int dpi = 0;
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
@SuppressWarnings("rawtypes")
Class c;
try {
c = Class.forName("android.view.Display");
@SuppressWarnings("unchecked")
Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
method.invoke(display, displayMetrics);
dpi = displayMetrics.heightPixels;
} catch (Exception e) {
e.printStackTrace();
}
return dpi;
}
/**
* 获取apk的版本号 currentVersionCode
*
* @param ctx
* @return
*/
public static int getAPPVersionCode(Context ctx) {
int currentVersionCode = 0;
PackageManager pm = ctx.getPackageManager();
try {
PackageInfo info = pm.getPackageInfo(ctx.getPackageName(), 0);
currentVersionCode = info.versionCode; // 版本号
} catch (Exception e) {
e.printStackTrace();
}
return currentVersionCode;
}
private static Toast mToast;
private static Handler mHandler = new Handler();
private static Runnable r = new Runnable() {
public void run() {
mToast.cancel();
}
};
public static void showToast(Context mContext, String text) {
mHandler.removeCallbacks(r);
if (mToast != null)
mToast.setText(text);
else
mToast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
mHandler.postDelayed(r, 1500);
mToast.show();
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(float dpValue) {
final float scale = SmartApplication.getApplication().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int px2dip(float pxValue) {
final float scale = SmartApplication.getApplication().getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @return
*/
public static int sp2px(float spValue) {
final float fontScale = SmartApplication.getApplication().getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
//英文占1byte,非英文(可认为是中文)占2byte,根据这个特性来判断字符
public static boolean checkCharEn(char ch) {
if ((ch + "").getBytes().length == 1) {
return true;//英文
} else {
return false;//中文
}
}
/**
* 判断是否是手机号
*
* @param mobiles
* @return
*/
public static boolean isMobileNum(String mobiles) {
//必须以13,15(除154),18,17,14(5,7,9)开头,11位数字
String regExp = "^((13[0-9])|(15[^4,\\D])|(18[0-9])|(17[^4,\\D])|(14[5,7,9]))\\d{8}$";
Pattern p = Pattern.compile(regExp);
Matcher m = p.matcher(mobiles);
return m.matches();
}
/**
* 判断是否含有特殊字符
*
* @param str
* @return true为包含,false为不包含
*/
public static boolean isSpecialChar(String str) {
String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]|\n|\r|\t";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
return m.find();
}
/**
* 判断qq weChat是否可用
*
* @param context
* @return
*/
public static boolean isAuthClientAvailable(Context context, String packageName) {
final PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals(packageName)) {
return true;
}
}
}
return false;
}
/**
* 临时保存图片到SD卡根目录,用于QQ分享
*
* @param bm
*/
public static void temporarilySaveImageToSDCamera(Bitmap bm) {
String s = Environment.getExternalStorageDirectory().getPath();
File f = new File(s + "/SK_interjoy_saveBm" + ".jpg");
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static final String TAG = "Utils";
/**
* 图片的二进制数据
*
* @param bmp
* @param needRecycle
* @return
*/
public static byte[] bmpToByteArray(Bitmap bmp, boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static String bmp2Base64String(Bitmap bmp) {
byte[] datum = Utils.bmpToByteArray(bmp, false);
return Base64.encodeToString(datum, 0, datum.length, Base64.DEFAULT);
}
//获得本地图像
public static Bitmap getLocalBitmap(String uri) {
try {
FileInputStream fis = new FileInputStream(uri);
Bitmap b = BitmapFactory.decodeStream(fis);
fis.close();
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Bitmap readBitmapByFileName(String fileName) {
try {
FileInputStream fis = SmartApplication.getApplication().openFileInput(fileName);
Bitmap b = BitmapFactory.decodeStream(fis);
fis.close();
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 把文件存为缓存传送
public static void saveBitmap2Local(Bitmap bmp, String fileName, SKStringCallBack stringCallBack) {
try {
// 打开文件输出流
FileOutputStream fos = SmartApplication.getApplication().openFileOutput(fileName, MODE_PRIVATE);
fos.write(bmpToByteArray(bmp, true));
fos.close();
stringCallBack.getResult("OK");
} catch (Exception e) {
e.printStackTrace();
stringCallBack.getResult(e.toString());
}
}
public static String getDeviceId(Context context) {
String deviceId = (String) SharedPreferencesUtil.getParam(SP_NAME_SYSTEM_INFO, SP_KEY_DEVICE_ID, "");
if (TextUtils.isEmpty(deviceId)) {
deviceId = getMD5(getDeviceInfo(context));
SharedPreferencesUtil.setParam(SP_NAME_SYSTEM_INFO, SP_KEY_DEVICE_ID, deviceId);
}
return deviceId;
}
/**
* deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符
* 渠道标志为:
* andriod(a_)
* 识别符来源标志:-
* 1, wifi mac地址(wifi_);
* 2, IMEI(imei_);
* 3, 序列号(sn_);
* 4, id:随机码。若前面的都取不到时,则随机生成一个随机码,需要缓存。
*
* @param context
* @return
*/
private static String getDeviceInfo(Context context) {
StringBuilder deviceId = new StringBuilder();
// 渠道标志
deviceId.append("a_");
try {
//wifi mac地址
// WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// WifiInfo info = wifi.getConnectionInfo();
// String wifiMac = info.getMacAddress();
// if (!TextUtils.isEmpty(wifiMac)) {
// deviceId.append("wifi");
// deviceId.append(wifiMac);
// return deviceId.toString();
// }
//IMEI(imei)
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String imei = tm.getDeviceId();
if (!TextUtils.isEmpty(imei)) {
deviceId.append("imei_");
deviceId.append(imei);
return deviceId.toString();
}
//序列号(sn)
String sn = tm.getSimSerialNumber();
if (!TextUtils.isEmpty(sn)) {
deviceId.append("sn_");
deviceId.append(sn);
return deviceId.toString();
}
//如果上面都没有, 则生成一个id:随机码
String uuid = UUID.randomUUID().toString();
if (!TextUtils.isEmpty(uuid)) {
deviceId.append("id_");
deviceId.append(uuid);
return deviceId.toString();
}
} catch (Exception e) {
e.printStackTrace();
deviceId.append("id_").append(UUID.randomUUID().toString());
}
return deviceId.toString();
}
/**
* 获取String的MD5值
*
* @param info 字符串
* @return 该字符串的MD5值 返回值为十六进制的32位长度的字符串
*/
private static String getMD5(String info) {
try {
//获取 MessageDigest 对象,参数为 MD5 字符串,表示这是一个 MD5 算法(其他还有 SHA1 算法等):
MessageDigest md5 = MessageDigest.getInstance("MD5");
//update(byte[])方法,输入原数据
//类似StringBuilder对象的append()方法,追加模式,属于一个累计更改的过程
md5.update(info.getBytes("UTF-8"));
//digest()被调用后,MessageDigest对象就被重置,即不能连续再次调用该方法计算原数据的MD5值。可以手动调用reset()方法重置输入源。
//digest()返回值16位长度的哈希值,由byte[]承接
byte[] md5Array = md5.digest();
//byte[]通常我们会转化为十六进制的32位长度的字符串来使用,本文会介绍三种常用的转换方法
return new BigInteger(1, md5Array).toString(16);
} catch (NoSuchAlgorithmException e) {
return "";
} catch (UnsupportedEncodingException e) {
return "";
}
}
/**
* 需要权限:android.permission.GET_TASKS
* 判断Activity是否为非前台程序
*
* @param mActivity
* @return true:非前台,false:前台
*/
public static boolean isToBackground(Activity mActivity) {
ActivityManager am = (ActivityManager) mActivity
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
if (tasks != null && !tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
// Logs.d(TAG, "topActivity:" + topActivity.flattenToString());
if (!topActivity.getPackageName().equals(mActivity.getPackageName())) {
return true;
}
}
return false;
}
public static String HanZiToPinYin(String chines) {
StringBuilder sb = new StringBuilder();
char[] chars = chines.toCharArray();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);
format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);
try {
for (char hanzi : chars) {
if (hanzi >= 0x4e00 && hanzi <= 0x9fa5) { //是否在汉字范围内
sb.append(PinyinHelper.toHanyuPinyinStringArray(hanzi, format)[0] + "\t");
} else //如果不是汉字就原字符添加,例如数字字母标点
sb.append(String.valueOf(hanzi));
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
//返回拼音
return sb.toString();
}
}
其中使用到的jar,下载链接https://download.csdn.net/download/iblade/10685511