公司项目需求,需要增加第三方登录,这里先介绍微信,其他的大同小异。
思路很简单:
第一,统一一个入口,定义规范一些方法和回调。
第二,根据不同的第三方平台,建立各自的管理中心,负责对应平台的具体逻辑。
第三,利用类型参数,把第一和第二部关联起来。
建立统一入口:
public class ShareAndLoginManager {
private final String TAG = "ShareAndLoginManager";
public interface ShareListener {
void onShareSuccess(ShareType type);
void onShareFailed(ShareType type, int code, String message);
void onShareCancel(ShareType type, int requestCode, int resultCode);
}
public interface LoginListener {
void onLoginSuccess(LoginType type, String name, String headUrl, int sex, String code);
void onLoginFailed(LoginType type, int code, String message);
void onLoginCancel(LoginType type, int requestCode, int resultCode);
void onLoginDenied(LoginType type);
}
public enum LoginType {
kLoginTypeWeChat,
}
public enum ShareType {
kShareTypeSystem,
kShareTypeWeChat,
kShareTypeWeChatTimeline,
kShareTypeWeChatFriends,
}
private ShareType mCurrentShareType;
private static ShareAndLoginManager _instance = null;
public static synchronized ShareAndLoginManager getInstance() {
if (null == _instance) _instance = new ShareAndLoginManager();
return _instance;
}
private ShareListener mListener = null;
private LoginListener mLoginListener = null;
public void loginByThirdParty(Activity activity, LoginType type, @Nullable LoginListener listener) {
this.mLoginListener = listener;
switch (type) {
case kLoginTypeWeChat: {
WechatInstanceManager.Companion.getInstance().loginByWx(activity);
}
break;
}
}
public void shareImage(Activity activity, ShareType type, Object object, @Nullable ShareListener listener) {
this.mListener = listener;
this.mCurrentShareType = type;
switch (type) {
case kShareTypeWeChatFriends: {
if (object instanceof Bitmap) {
Bitmap bitmap = (Bitmap) object;
WechatInstanceManager.Companion.getInstance().shareImageToWx(false, activity, bitmap);
}
}
break;
case kShareTypeWeChatTimeline: {
if (object instanceof Bitmap) {
Bitmap bitmap = (Bitmap) object;
WechatInstanceManager.Companion.getInstance().shareImageToWx(true, activity, bitmap);
}
}
break;
}
}
public void shareWeb(Activity activity, ShareType type, String title, String content, String iconUrl,
Bitmap iconBitmap, String webUrl, @Nullable ShareListener listener) {
this.mListener = listener;
this.mCurrentShareType = type;
switch (type) {
case kShareTypeWeChatFriends: {
WechatInstanceManager.Companion.getInstance().shareWebToWx(false, activity, title, content, iconBitmap, webUrl);
}
break;
case kShareTypeWeChatTimeline: {
WechatInstanceManager.Companion.getInstance().shareWebToWx(true, activity, title, content, iconBitmap, webUrl);
}
break;
case kShareTypeSystem: {
shareWebToSystem(activity, title, webUrl, 0);
}
break;
}
}
private void shareWebToSystem(Activity activity, String title, String webUrl, int requestCode) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, title + webUrl);//注意:这里只是分享文本内容
sendIntent.setType("text/plain");
activity.startActivityForResult(sendIntent, requestCode);
}
public void onShareSuccess(ShareType type) {
if (null != this.mListener) {
this.mListener.onShareSuccess(type);
}
}
public void onShareCancel(ShareType type, int requestCode, int resultCode) {
if (null != this.mListener) {
this.mListener.onShareCancel(type, requestCode, resultCode);
}
}
public void onShareFailed(ShareType type, int code, String message) {
if (null != this.mListener) {
this.mListener.onShareFailed(type, code, message);
}
}
public void onLoginSuccess(LoginType type, String name, String headUrl, int sex, String code) {
if (null != this.mLoginListener) {
this.mLoginListener.onLoginSuccess(type, name, headUrl, sex, code);
}
}
public void onLoginCancel(LoginType type, int requestCode, int resultCode) {
if (null != this.mLoginListener) {
this.mLoginListener.onLoginCancel(type, requestCode, resultCode);
}
}
public void onLoginFailed(LoginType type, int code, String message) {
if (null != this.mLoginListener) {
this.mLoginListener.onLoginFailed(type, code, message);
}
}
public void onLoginDenied(LoginType type) {
if (null != this.mLoginListener) {
this.mLoginListener.onLoginDenied(type);
}
}
public void onActivityResult(Activity activity, final int requestCode, final int resultCode, Intent data) {
}
}
建立微信的处理中心:
class WechatInstanceManager private constructor() {
private val TAG = "WechatInstanceManager"
companion object {
val instance = InstanceHolder.holder
private var iwxapi: IWXAPI? = null
fun getWechatApi(context: Context): IWXAPI {
if (iwxapi == null) {
iwxapi = WXAPIFactory.createWXAPI(context, null)
iwxapi!!.registerApp(Config.WECHAT_APP_ID)
}
return iwxapi!!
}
}
fun loginByWx(activity: Activity) {
val iwxapi = getWechatApi(activity)
if (iwxapi.isWXAppInstalled) {
val request = SendAuth.Req()
request.scope = "snsapi_userinfo"
request.state = "wechat_login"
iwxapi.sendReq(request)
} else {
ToastUtil.showToast(R.string.no_install_app, ToastUtil.LENGTH_SHORT)
}
}
fun shareImageToWx(isTimeline: Boolean, activity: Activity, bitmap: Bitmap) {
val iwxapi = getWechatApi(activity)
if (iwxapi.isWXAppInstalled) {
val imageObject = WXImageObject(bitmap)
val message = WXMediaMessage()
message.mediaObject = imageObject
val request = SendMessageToWX.Req()
request.transaction = buildWxTransaction("img")
request.message = message
request.scene =
if (isTimeline) SendMessageToWX.Req.WXSceneTimeline else SendMessageToWX.Req.WXSceneSession
val sharedResult = iwxapi.sendReq(request)
Log.d(TAG, "result=$sharedResult")
} else {
ToastUtil.showToast(R.string.no_install_app, ToastUtil.LENGTH_SHORT)
}
}
fun shareWebToWx(
isTimeLine: Boolean,
activity: Activity,
title: String,
content: String,
iconBitmap: Bitmap,
webUrl: String
) {
}
private fun buildWxTransaction(type: String?): String? {
return if (type == null) System.currentTimeMillis()
.toString() else type + System.currentTimeMillis()
}
private object InstanceHolder {
val holder = WechatInstanceManager()
}
}
微信结果的返回处理:
class WXEntryActivity : WeChatHandleActivity(), IWXAPIEventHandler {
private var api: IWXAPI? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
api = getWechatApi(this);
try {
api?.handleIntent(intent, this)
} catch (e: Exception) {
}
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
}
override fun onReq(req: BaseReq) {
}
override fun onResp(resp: BaseResp) {
if (resp.type == ConstantsAPI.COMMAND_SENDAUTH) {
when (resp.errCode) {
BaseResp.ErrCode.ERR_OK -> {
if (resp.type == ConstantsAPI.COMMAND_SENDAUTH) {
val authResp: SendAuth.Resp = resp as SendAuth.Resp
val code: String = authResp.code
// getAccessToken(code)
ShareAndLoginManager.getInstance().onLoginSuccess(ShareAndLoginManager.LoginType.kLoginTypeWeChat,
"",
"",
0,
code)
}
}
}
}
finish()
}
private fun getAccessToken(code: String) {
//这个接口需用get请求
val path =
("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + Config.WECHAT_APP_ID + "&secret="
+ Config.WECHAT_APP_SECRET + "&code=" + code + "&grant_type=authorization_code")
val client = OkHttpClient()
val request = Request.Builder()
.url(path)
.build()
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
finish()
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (null != response.cacheResponse()) {
val str = response.cacheResponse().toString()
} else {
val body = response.body()!!.string()
val str = response.networkResponse().toString()
runOnUiThread {
try {
val jsonObject = JSONObject(body)
val access_token = jsonObject.getString("access_token")
val expires_in = jsonObject.getInt("expires_in")
val refresh_token = jsonObject.getString("refresh_token")
val openid = jsonObject.getString("openid")
val scope = jsonObject.getString("scope")
val unionid = jsonObject.getString("unionid")
getAsyncPersonData("https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid")
} catch (e: JSONException) {
e.printStackTrace()
}
}
}
}
})
}
private fun getAsyncPersonData(url: String) {
val client = OkHttpClient()
val request = Request.Builder()
.url(url)
.build()
val response: Response? = null
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
finish()
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
if (null != response.cacheResponse()) {
val str = response.cacheResponse().toString()
} else {
val bod = response.body()!!.string()
val str = response.networkResponse().toString()
Log.e("bod", "bod---$bod")
runOnUiThread {
try {
val jsonObject = JSONObject(bod)
val nickname = jsonObject.getString("nickname") //微信用户昵称
val headImgUrl = jsonObject.getString("headimgurl") //微信用户头像
val unionId = jsonObject.getString("unionid") //用户统一标识
val sex = jsonObject.getInt("sex") //性别
ShareAndLoginManager.getInstance().onLoginSuccess(
ShareAndLoginManager.LoginType.kLoginTypeWeChat,
nickname,
headImgUrl,
sex,
unionId
)
finish()
} catch (e: JSONException) {
finish()
e.printStackTrace()
}
}
}
}
})
}
}
这里是处理登录的流程,分别有3步,获取code、获取AccessToken、获取用户个人数据。具体需要调用到哪一步,看跟自己项目服务器的需要,我这里只需要第一步获取code就行。
配置文件
<!-- Optional 微信分享回调,wxapi必须在包名路径下,否则回调不成功-->
<activity
android:name=".wxapi.WXEntryActivity"
android:exported="true"
android:taskAffinity="${applicationId}"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
使用:
private fun loginByWechat(){
ShareAndLoginManager.getInstance().loginByThirdParty(this,ShareAndLoginManager.LoginType.kLoginTypeWeChat,
object :ShareAndLoginManager.LoginListener{
override fun onLoginSuccess(
type: ShareAndLoginManager.LoginType?,
name: String?,
headUrl: String?,
sex: Int,
code: String?
) {
Log.d("TAG","code=$code")
//微信验证成功,接下来在这里继续你想实现的逻辑。
}
override fun onLoginFailed(
type: ShareAndLoginManager.LoginType?,
code: Int,
message: String?
) {
ToastUtil.showToast("登录失败")
}
override fun onLoginCancel(
type: ShareAndLoginManager.LoginType?,
requestCode: Int,
resultCode: Int
) {
ToastUtil.showToast("取消登录")
}
override fun onLoginDenied(type: ShareAndLoginManager.LoginType?) {
}
})
}