手机QQ

全部目录

开发者指引

接入指南

加入QQJSSDK.framework ,其中包含了JS API的插件管理器方法. 下载所需js文件 包括:jsbridge.js。 cdn

备注
jsbridge.js : 白名单内的为可以走sdk.js中的mqq.invoke逻辑;
              如果不在白名单,走老逻辑QZAppExternal;
[最终协议格式为](jsbridge://namespace/method?param=test¶m2=xxx¶m3=yyy#123)

android开发指引

导入SDK : 导入开发工具包QQJsSdkQB.jar(若项目已经引入TBS,请引入TBSQQJsSDK.jar)

备注
SDK中包含:
- 插件基类WebViewPlugin
- 插件引擎WebViewPluginEngine
- 引擎内的插件容器及插件配置WebViewPluginContainer与WebViewPluginConfig

自定义插件 : 继承类WebViewPlugin

类WebViewPlugin说明:


public DefaultPluginRuntime mRuntime;//插件的运行时对象, 可以获取当前context、Activity、WebView等实例
protected void onCreate(){} // 插件创建时被调用, 可以重载做插件的初始化工作, 建议不要放太多的逻辑, 一些不常用的数据可以放到首次使用时初始化.
protected void onDestroy(){} //插件销毁时被调用, 可以重载做插件的回收工作.
/**
    Webview里有JS调用会执行这个方法, 重载以实现自己的API
    @param url 触发接口的jsbridge伪协议
    @param pkgName 接口的包名
    @param method 方法名
    @param args[] 参数
    @return 根据pkgName和method判断是否处理, true表示已处理, API调用结束, false表示未处理, API调用会继续传给下一个插件处理.
*/
protected boolean handleJsRequest(String url, String pkgName, String method, String... args) {..}
public void onActivityResult(Intent intent, byte requestCode, int resultCode){}//启动activity
public void startActivityForResult(Intent intent, byte requestCode){}//获取来自activity的result
public void callJs(String func, JSONObject data){}//用于回传数据给web端,参见getResult

Example:ShortcutPlugin

 @Override
    protected boolean handleJsRequest(String url, String pkgName, String method, String... args) {
        if ("addShortcut".equals(method)) {
            try {
                JSONObject json = new JSONObject(args[0]);
                //成功、失败回调
                callback = json.optString(KEY_CALLBACK);
                Shortcut shortcut = new Shortcut();
                shortcut.setScheme(json.optString("scheme"));
                shortcut.setTitle(json.optString("title"));
                shortcut.setIcon(json.optString("icon"));
                doAddShortcut(shortcut);//内部逻辑
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return super.handleJsRequest(url, pkgName, method, args);
    }

调用插件引擎 :

- 在layout和java代码中使用CustomWebView代替系统的WebView类

- 参考如下onCreate初始化,其中AuthorizeConfig用于权限控制,需要继承实现调用插件引擎的insertPlugin方法将所需插件list注册到插件引擎的插件容器中

- 实现WebViewPluginContainer接口,在pluginStartActivityForResult和onActivityResult实现result的派发

- 在onResume/onPause/onDestory中加入相应的解决内存泄漏的代码

Example :

import com.tencent.mobileqq.webviewplugin.*;// import webviewplugin 的所有类
public class MyActivity extends Activity implements WebViewPluginContainer{// 声明实现 WebViewPluginContainer
    CustomWebView webview;
    protected WebViewPluginEngine mPluginEngine;
    private PluginInfo[] pluginInfos= {new PluginInfo(ShareApiPlugin.class,"share", "mqq.share.* API", "1.0")};
    protected void onCreate(Bundle savedInstanceState) {
        webview=(CustomWebView) this.findViewById(R.id.webview);
        mPluginEngine = new WebViewPluginEngine(WebViewPluginConfig.list,new DefaultPluginRuntime(webview,this));// 设置 common API
        mPluginEngine.insertPlugin(pluginInfos);// 将插件添加入引擎中,pluginInfos为插件list
        webview.setWebViewClient(new CustomWebViewClient(mPluginEngine));// 监听WebView
        webview.setWebChromeClient(new CustomWebChromeClient(mPluginEngine));
        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setUserAgentString("QQJSSDK/1.0.0 Android");
        AuthorizeConfig.setClass(com.example.demo.QQAuthorizeConfig.class);// 设置 API 的权限配置
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (Build.VERSION.SDK_INT >= 11) {
            webview.onResume();
        } else {
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        if (Build.VERSION.SDK_INT >= 11) {
            webview.onPause();
        } else {
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPluginEngine.onDestroy(); //重要, 一定要加, 防止内存泄露
        webview.destroy();
    }
    @Override
    public int pluginStartActivityForResult(WebViewPlugin plugin, Intent intent, byte requestCode) {
        return WebViewPlugin.defaultPluginStartActivityForResult(this, plugin, intent, requestCode);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (WebViewPlugin.defaultPluginOnActivityResult(mPluginEngine, requestCode, resultCode, data)) {
            return;
        }
    }
}

分发请求 : 调用插件引擎的handleJsRequest将请求分发给对应的插件。

iOS开发指引

引入自定义UI控制类 :引入自己的UIViewController类,在该类类别中遵循AppWebViewProtocol协议,并实现协议方法

@interface AppWebViewController : UIViewController
@end

@interface AppWebViewController(JSAPI) <AppWebViewProtocol>
-(NSURL*)getPageURL;
-(NSString *)executeJsScript:(NSString*)script;
@end

嵌入Webview :在自己的UIViewController中嵌入UIWebview,并按照正常的UIWebview加载方法进行加载,并且必须实现UIWebViewDelegate中的如下方法

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{

    //把请求交给webview插件管理器处理,以后所有schema请求都放这里面注册成插件来处理
    if ([[QQJSWebViewPluginEngine getInstance] handleSchemaRequest:request.URL fromWebview:self]) {
        return NO;
    }

    return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventLoadStart userInfo:nil fromWebview:self];
    //TO DO ....
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventLoadFinish userInfo:nil fromWebview:self];
    //TO DO ....
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventLoadFail userInfo:@{@"error":error} fromWebview:self];
    //TO DO ....
}

插件进行事件处理 : 在UIViewController的生命周期方法中让插件进行事件处理

-(void)viewWillAppear:(BOOL)animated {
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventWillAppear userInfo:nil fromWebview:self];
    //TO DO ....
}
- (void)viewDidAppear:(BOOL)animated{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventDidAppear userInfo:nil fromWebview:self];
    //TO DO ....
}
- (void)viewWillDisappear:(BOOL)animated{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWebViewEventWillDisappear userInfo:nil fromWebview:self];
    //TO DO ....
}
- (void)viewDidDisappear:(BOOL)animated{
    //TO DO ....
    [[QQWebViewPluginEngine getInstance] handleEvent:QQWEbViewEventDidDisappear userInfo:nil fromWebview:self];
    //页面被销毁时插件也要销毁
    if([self isOrphan:self])
    {
       [[QQWebViewPluginEngine getInstance] handleWebviewDestory:self];
    }
    //TO DO ....
}
- (BOOL)isOrphan:(UIViewController *)viewController{
    if (viewController) {
        if (viewController.parentViewController && [viewController.parentViewController isKindOfClass:[UINavigationController class]]) {
            //如果viewController是放在navigationController里的,我们应该判断该navigationController
            return [self isOrphan:viewController.navigationController];
        }
        else {
            //否则直接判断,如果viewController又没parent又没被present,则返回YES
            return !viewController.parentViewController && !viewController.presentingViewController;
        }
    }
    return YES;
}

view的生命周期方法需按照上面的实现方法进行,绿色TO DO部分可用来写入其他处理.完成上面步骤即可开始调用JS API

建立自己的插件类 : 建立自己的插件类,并继承QQJSBridgePluginHelper

#import <Foundation/Foundation.h>
#import "QQJSBridgePluginHelper.h"
@interface QQJSBridgeDemoPlugin : QQJSBridgePluginHelper

@end

注册插件 : 在QQWebViewPluginConfigs.h中注册该插件,其中func字段的值是插件的模块名

@"com.tencent.sng.app.jsbridge.device": @{
                    @"cls":     [QQJSBridgeDemoPlugin class],
                    @"desc":    @"JSBridge Demo Module Plugin",
                    @"ver":     @"1.0.0",
                    @"func":    @[@"device"]
                    },

实现自定义插件方法并命名 : 在该类中实现自己的插件方法按照handleJsBridgeRequest模块名方法名的格式来命名插件方法

#import "QQJSBridgeDemoPlugin.h"
@implementation QQJSBridgeDemoPlugin

#pragma mark - mqq.offline

#define kJsCallback @"callback"
#define kJS_NULL_STR @"null"
#define kSyncCallTimeout dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC)
#define kAsyncCallTimeout DISPATCH_TIME_FOREVER

-(id)init
{
    self = [super init];

    if (self) {

    }

    return self;
}

- (id)handleJsBridgeRequest_device_isMobileQQ:(NSDictionary*)params
{
    NSLog(@"handleJsBridgeRequest_device_isMobileQQ");
    return nil;
}

//旧接口:执行更新并返回更新结果
- (id)handleJsBridgeRequest_offline_update:(NSDictionary*)params
{
    //业务BID
    NSString *bid = [NSString stringWithFormat:@"%@", [params objectForKey:@"bid"]];
    NSString *updateJsCallback = [params objectForKey:kJsCallback];

    //防止参数为空
    if (!updateJsCallback || !bid)
    {
        [self evaluateOfflineJavascript:updateJsCallback event:0 ret:0 response:nil];
        return nil;
    }

    //通知JS:event为0,代表本地是否缓存
    [self evaluateOfflineJavascript:updateJsCallback event:0 ret:0 response:nil];
    return nil;
}

- (void)evaluateOfflineJavascript:(NSString*)callback event:(int)event ret:(int)ret response:(NSString*)response
{
    //需要执行的JS脚本
    NSString *script = [NSString stringWithFormat:@"%@(%d, %d, %@)", callback, event, ret, response ? response : kJS_NULL_STR];
    [self evaluateOfflineJavascript:script];
}

- (void)evaluateOfflineJavascript:(NSString*)script
{
    if ([NSThread isMainThread])
    {
        [self.webViewController executeJsScript:script];
    }
    else
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.webViewController executeJsScript:script];
        });
    }
}


@end

开发者规范

综述 : 开发者开发时,除了需要满足每个接口的规范限制、调用频率限制外,还需特别注意模版消息、用户数据等敏感信息的使用规范。

涉及用户数据时 :

您的服务需要收集用户任何数据的,必须事先获得用户的明确同意,且仅应当收集为运营及功能实现目的而必要的用户数据, 同时应当告知用户相关数据收集的目的、范围及使用方式等,保障用户知情权。 您收集用户的数据后,必须采取必要的保护措施,防止用户数据被盗、泄漏等。 如果腾讯认为您收集、使用用户数据的方式,可能损害用户体验,腾讯有权要求您删除相关数据并不得再以该方式收集、使用用户数据。 一旦您停止使用本服务,或腾讯基于任何原因终止您使用本服务,您必须立即删除全部因使用本服务而获得的数据(包括各种备份), 且不得再以任何方式进行使用。

其他规范 :

请勿设置或发布任何违反相关法规、公序良俗、社会公德等的玩法、内容等。 请勿公开表达或暗示,您与腾讯之间存在合作关系,包括但不限于相互持股、商业往来或合作关系等,或声称腾讯对您的认可。 完整的开发者规范和接口限制,请详见开发者接口文档