Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

添加两个方法,支持判断QQ是否已登录及拉起手机QQ聊天 #23

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ android {
resourcePrefix 'tencent_kit'

defaultConfig {
minSdkVersion 16
minSdkVersion 16

// library 混淆 -> 随 library 引用,自动添加到 apk 打包混淆
consumerProguardFiles 'consumer-proguard-rules.pro'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzonePublish;
import com.tencent.connect.share.QzoneShare;
import com.tencent.open.im.IM;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
Expand Down Expand Up @@ -63,12 +64,14 @@ private static class TencentRetCode {

private static final String METHOD_REGISTERAPP = "registerApp";
private static final String METHOD_ISINSTALLED = "isInstalled";
private static final String METHOD_ISREADY = "isReady";
private static final String METHOD_LOGIN = "login";
private static final String METHOD_LOGOUT = "logout";
private static final String METHOD_SHAREMOOD = "shareMood";
private static final String METHOD_SHAREIMAGE = "shareImage";
private static final String METHOD_SHAREMUSIC = "shareMusic";
private static final String METHOD_SHAREWEBPAGE = "shareWebpage";
private static final String START_CONVERSATION = "startConversation";

private static final String METHOD_ONLOGINRESP = "onLoginResp";
private static final String METHOD_ONSHARERESP = "onShareResp";
Expand All @@ -86,6 +89,7 @@ private static class TencentRetCode {
private static final String ARGUMENT_KEY_TARGETURL = "targetUrl";
private static final String ARGUMENT_KEY_APPNAME = "appName";
private static final String ARGUMENT_KEY_EXTINT = "extInt";
private static final String ARGUMENT_KEY_QQ = "qq";

private static final String ARGUMENT_KEY_RESULT_RET = "ret";
private static final String ARGUMENT_KEY_RESULT_MSG = "msg";
Expand All @@ -107,7 +111,7 @@ private TencentKitPlugin(Registrar registrar, MethodChannel channel) {
}

@Override
public void onMethodCall(MethodCall call, @NonNull Result result) {
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (METHOD_REGISTERAPP.equals(call.method)) {
final String appId = call.argument(ARGUMENT_KEY_APPID);
// final String universalLink = call.argument(ARGUMENT_KEY_UNIVERSALLINK);
Expand All @@ -129,6 +133,8 @@ public void onMethodCall(MethodCall call, @NonNull Result result) {
}
}
result.success(isInstalled);
} else if (METHOD_ISREADY.equals(call.method)) {
result.success(tencent != null && tencent.isReady());
} else if (METHOD_LOGIN.equals(call.method)) {
login(call, result);
} else if (METHOD_LOGOUT.equals(call.method)) {
Expand All @@ -141,6 +147,8 @@ public void onMethodCall(MethodCall call, @NonNull Result result) {
shareMusic(call, result);
} else if (METHOD_SHAREWEBPAGE.equals(call.method)) {
shareWebpage(call, result);
} else if (START_CONVERSATION.equals(call.method)) {
startConversation(call, result);
} else {
result.notImplemented();
}
Expand Down Expand Up @@ -169,6 +177,8 @@ public void onComplete(Object o) {
int expiresIn = !object.isNull(ARGUMENT_KEY_RESULT_EXPIRES_IN) ? object.getInt(ARGUMENT_KEY_RESULT_EXPIRES_IN) : 0;
long createAt = System.currentTimeMillis();
if (!TextUtils.isEmpty(openId) && !TextUtils.isEmpty(accessToken)) {
tencent.setOpenId(openId);
tencent.setAccessToken(accessToken, String.valueOf(expiresIn));
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_SUCCESS);
map.put(ARGUMENT_KEY_RESULT_OPENID, openId);
map.put(ARGUMENT_KEY_RESULT_ACCESS_TOKEN, accessToken);
Expand Down Expand Up @@ -365,6 +375,41 @@ private void shareWebpage(MethodCall call, Result result) {
result.success(null);
}

private void startConversation(MethodCall call, Result result) {
if (tencent == null) {
result.error(String.valueOf(IM.IM_UNKNOWN_TYPE), "Should register app at first", null);
return;
}
if (!tencent.isReady()) {
result.error(String.valueOf(IM.IM_UNKNOWN_TYPE), "Should login at first", null);
return;
}
String qq = call.argument(ARGUMENT_KEY_QQ);
android.app.Activity activity = registrar.activity();
String packageName = activity.getApplicationContext().getPackageName();
int ret = tencent.startIMAio(activity, qq, packageName);
if (ret == IM.IM_SUCCESS) {
result.success("0");
return;
}
String errorMsg;
switch (ret) {
case IM.IM_SHOULD_DOWNLOAD:
errorMsg = "Should download latest version of MobileQQ";
break;
case IM.IM_UIN_EMPTY:
case IM.IM_LENGTH_SHORT:
case IM.IM_UIN_NOT_DIGIT:
errorMsg = "QQ number is invalid";
break;
case IM.IM_UNKNOWN_TYPE:
default:
errorMsg = "Unknown type";
break;
}
result.error(String.valueOf(ret), errorMsg, null);
}

private IUiListener shareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Expand Down
24 changes: 23 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show PlatformException;
import 'package:okhttp_kit/okhttp_kit.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as path_provider;
Expand Down Expand Up @@ -75,7 +76,9 @@ class _HomeState extends State<Home> {
ListTile(
title: const Text('环境检查'),
onTap: () async {
String content = 'tencent: ${await _tencent.isInstalled()}';
bool isInstalled = await _tencent.isInstalled();
bool isReady = await _tencent.isReady();
String content = 'isInstalled=$isInstalled, isReady=$isReady';
_showTips('环境检查', content);
},
),
Expand All @@ -90,6 +93,10 @@ class _HomeState extends State<Home> {
ListTile(
title: const Text('获取用户信息'),
onTap: () async {
if (!await _tencent.isReady()) {
_showTips('Error', '请先登录');
return;
}
if (_loginResp != null &&
_loginResp.isSuccessful() &&
!_loginResp.isExpired()) {
Expand All @@ -110,6 +117,10 @@ class _HomeState extends State<Home> {
ListTile(
title: const Text('获取UnionID'),
onTap: () async {
if (!await _tencent.isReady()) {
_showTips('Error', '请先登录');
return;
}
if (_loginResp != null &&
_loginResp.isSuccessful() &&
!_loginResp.isExpired()) {
Expand Down Expand Up @@ -175,6 +186,17 @@ class _HomeState extends State<Home> {
);
},
),
ListTile(
title: const Text('拉起手Q会话窗口'),
onTap: () async {
try {
await _tencent.startConversation('1032694760');
} on PlatformException catch (e) {
//错误码参见QQ互联文档:https://wiki.connect.qq.com/%E8%81%8A%E5%A4%A9
_showTips('Error', '${e.code} - ${e.message}');
}
},
),
],
),
);
Expand Down
3 changes: 3 additions & 0 deletions ios/Classes/TencentKitPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {

static NSString *const METHOD_REGISTERAPP = @"registerApp";
static NSString *const METHOD_ISINSTALLED = @"isInstalled";
static NSString *const METHOD_ISREADY = @"isReady";
static NSString *const METHOD_LOGIN = @"login";
static NSString *const METHOD_LOGOUT = @"logout";
static NSString *const METHOD_SHAREMOOD = @"shareMood";
Expand Down Expand Up @@ -96,6 +97,8 @@ - (void)handleMethodCall:(FlutterMethodCall *)call
// 普通大众版 > 办公简洁版
BOOL isInstalled = [TencentOAuth iphoneQQInstalled] || [TencentOAuth iphoneTIMInstalled];
result([NSNumber numberWithBool:isInstalled]);
} else if ([METHOD_ISREADY isEqualToString:call.method]) {
result(FlutterMethodNotImplemented);
} else if ([METHOD_LOGIN isEqualToString:call.method]) {
[self login:call result:result];
} else if ([METHOD_LOGOUT isEqualToString:call.method]) {
Expand Down
24 changes: 24 additions & 0 deletions lib/src/tencent.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ class Tencent {

static const String _METHOD_REGISTERAPP = 'registerApp';
static const String _METHOD_ISINSTALLED = 'isInstalled';
static const String _METHOD_ISREADY = 'isReady';
static const String _METHOD_LOGIN = 'login';
static const String _METHOD_LOGOUT = 'logout';
static const String _METHOD_SHAREMOOD = 'shareMood';
static const String _METHOD_SHAREIMAGE = 'shareImage';
static const String _METHOD_SHAREMUSIC = 'shareMusic';
static const String _METHOD_SHAREWEBPAGE = 'shareWebpage';
static const String _METHOD_STARTCONVERSATION = 'startConversation';

static const String _METHOD_ONLOGINRESP = 'onLoginResp';
static const String _METHOD_ONSHARERESP = "onShareResp";
Expand All @@ -42,6 +44,7 @@ class Tencent {
static const String _ARGUMENT_KEY_TARGETURL = 'targetUrl';
static const String _ARGUMENT_KEY_APPNAME = 'appName';
static const String _ARGUMENT_KEY_EXTINT = 'extInt';
static const String _ARGUMENT_KEY_QQ = 'qq';

static const String _SCHEME_FILE = 'file';

Expand Down Expand Up @@ -101,6 +104,11 @@ class Tencent {
return _channel.invokeMethod(_METHOD_ISINSTALLED);
}

/// 检查Session及OpenId是否有效
Future<bool> isReady() async {
return _channel.invokeMethod(_METHOD_ISREADY);
}

/// 登录
Future<void> login({
@required List<String> scope,
Expand Down Expand Up @@ -313,4 +321,20 @@ class Tencent {
}
return _channel.invokeMethod(_METHOD_SHAREWEBPAGE, arguments);
}

/// 拉起手机QQ加好友聊天(仅支持Android)
Future<String> startConversation(String qq) {
assert(qq != null && qq.isNotEmpty);
if (!Platform.isAndroid) {
// iOS的支持需要自行封装这个协议:
// mqqapi://im/chat?chat_type=thirdparty2c&uin={QQ号}&version=1&src_type=app&open_id={OpenId的BASE64编码}&app_id={AppId的BASE64编码}&app_pkg_name={BundleId的BASE64编码}
throw UnsupportedError('Only supported on Android');
}
return _channel.invokeMethod(
_METHOD_STARTCONVERSATION,
<String, dynamic>{
_ARGUMENT_KEY_QQ: qq,
},
);
}
}