Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 3 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ android {
resourcePrefix 'tencent_kit'

defaultConfig {
minSdkVersion 16
minSdkVersion 16

manifestPlaceholders = [TENCENT_APP_ID: "222222"]

// 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,
},
);
}
}