腾讯 移动开发者接入指南

发布于 2022-01-03 15:02:00 字数 10973 浏览 1195 评论 0

接入指南

加入 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 和 ava 代码中使用 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 的生命周期方法需按照上面的实现方法进行,绿色 TODO 部分可用来写入其他处理,完成上面步骤即可开始调用 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

开发者规范

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

涉及用户数据时

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

其他规范

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

沧笙踏歌

文章 0 评论 0

山田美奈子

文章 0 评论 0

佚名

文章 0 评论 0

岁月无声

文章 0 评论 0

暗藏城府

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文