# 前端接口

微社区自研浏览器 SDK 包括 Android 与 iOS 版,2 个版本都覆写了浏览器的 alert、confirm、prompt 弹框,并提供了统一的 JS 接口

# 接入指引

# 前端页面添加 JS 文件

<script
  type="text/javascript"
  src="https://ossweb-img.qq.com/images/js/ingame_sdk/browser_adapt.js"
></script>
<script>
  if (typeof customBrowserInterface == 'object') {
    /*只有使用微社区自研浏览器SDK才能访问全局变量customBrowserInterface,使用其他浏览器打开微社区时customBrowserInterface为undefined*/
  }
</script>
1
2
3
4
5
6
7
8
9

# 前端页面添加返回按钮,用于返回上一页或返回游戏。

在 browser_adapt.js 里暴露了全局变量 customBrowserInterface 的一组接口,使用 demo 可参考 使用 Demo

为了避免出现白屏,加载第一个页面时会出现菊花状的进度条

# 微社区自研浏览器 SDK 的兼容性

  • Android 下兼容 X5 浏览器、系统自带的 WebView,优先使用 X5 浏览器,加载 X5 浏览器失败时就使用系统自带的 WebView
  • 使用 X5 浏览器时需指定 activity 的 android:process=":ingame_inner_webview",采用新进程来启动 X5 浏览器,不然会获取 JNIEnv 失败
  • iOS 下兼容 UIWebView、WKWebView,iOS8.2 及后续版本使用 WKWebView(从 iOS8 开始才有 WKWebView,iOS8.2 之前会偶现白屏问题),其他版本使用 UIWebView
  • 覆写了浏览器的 prompt 弹框(传特定 JSON 格式的参数时不会出现 prompt 弹框),JS 与 SDK 之间的交互通过 prompt 来实现,因此 browser_adapt.js 中的接口的返回值都是字符串
  • 调用 browser_adapt.js 中的接口时,如果 SDK 中没有对应的接口,就会返回空串 "",以此可以处理 JS 与 SDK 之间的兼容性

JS 与 SDK 之间的交互通过 prompt 来实现的原因如下:

  • Android 下可用 WebView 的 addJavascriptInterface 来暴露接口给 JS,但 Android4.2 之前通过反射机制 JS 可访问任意 java 类的函数,存在安全漏洞
  • iOS7 之前在 UIWebView 的 shouldStartLoadWithRequest 里处理交互,但 JS 调用无法获取返回值;iOS7 及后续版本的 UIWebView 可用 JavaScriptCore,JS 调用能获取返回值
  • iOS8 及后续版本可以使用 WKWebView,但 JS 调用无法获取返回值
  • 微社区的 JS 调用浏览器接口时需获取返回值,考虑到安全性、兼容性以及代码的可维护性,JS 与 SDK 之间的交互通过 prompt 来实现
  • 特别注意:Android 下 onJsPrompt 在主线程中运行(可直接修改 UI,但需新起子线程执行网络操作),而 iOS 下 runJavaScriptTextInputPanelWithPrompt 不是在主线程中运行(不能直接修改 UI)
  • 加载大图时(不管是 img 还是 canvas),Android 下的 WebView、iOS 下的 UIWebView 都会内存飙升,而 iOS 下的 WKWebView 内存基本无变化(WKWebView 是一个多进程组件,网络资源加载、UI 渲染都是在其他进程中执行,因此看上去似乎不占内存)
  • 频繁使用 prompt 与 SDK 交互时,SDK 的接口即使不做任何处理 iOS 下的 UIWebView、WKWebView 都会内存飙升,Android 下 的 WebView 内存基本无变化

注:Android(Java,通过 NDK 访问 C++)、iOS(Objective-C,直接访问 C++)、Unity(C#,最终会转换为 C++ 代码,也可以通过 DllImport 访问 C++),公共的代码可用 C++ 开发,各种平台都可以用,MSDK 就是这种方式

使用过程中遇到了任何问题请 RTX 联系:faniuxu(徐发牛)

# API

# 获取浏览器版本

customBrowserInterface.getCustomUserAgent()
//注:腾讯视频播放器会根据navigator.userAgent来判断如何播放视频,为了不干扰视频播放,修改navigator.userAgent时只是在末尾添加了空格 + 自定义串("Android TIEM Ingame Browser/0.5"、"iOS TIEM Ingame Browser/0.5",其中0.5为版本号,会动态变化)

customBrowserInterface.getVersion()
//判断customBrowserInterface.getCustomUserAgent()的返回值中的版本号,微社区自研浏览器SDK根据这个版本号来实现各版本之间的兼容
1
2
3
4
5

# 是否是微社区自研浏览器

customBrowserInterface.isCustomBrowser()
//返回值:true: 是 ; false: 不是
1
2

# 分享到 QQ 空间

customBrowserInterface.sendToQQ(1, title, desc, url, imgUrl)
//注:第一个参数固定为1,其他参数依次为标题、描述、点击后的跳转链接、图片的url,从第二个参数开始如果不需要某个参数可置为空串"",而不是null。
//如果没有出现分享界面,请检查imgUrl是否以"https://"开头,iOS下的app默认不允许直接加载http资源
1
2
3

# 分享给 QQ 好友

customBrowserInterface.sendToQQ(2, title, desc, url, imgUrl)
//注:第一个参数固定为2,其他参数请参考"分享到QQ空间"
1
2

# 分享到微信朋友圈

customBrowserInterface.sendToWeixinWithUrl(1, title, desc, url, imgUrl)
//注:第一个参数固定为1,其他参数请参考"分享到QQ空间",微信分享有很多限制,比如缩略图不能超过32kb等,具体限制可以查看微信官方文档:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317332&token=&lang=zh_CN
1
2

# 分享给微信好友

customBrowserInterface.sendToWeixinWithUrl(2, title, desc, url, imgUrl)
//注:第一个参数固定为2,其他参数请参考"分享到QQ空间"
1
2

# 是否装了微信

customBrowserInterface.isPlatformInstalled(1)
//返回值:"1": 安装了; "0": 没有安装
1
2

# 是否装了 QQ

customBrowserInterface.isPlatformInstalled(2)
//返回值:"1": 安装了;  "0": 没有安装
1
2

# 登录的帐号类型

customBrowserInterface.getAccountType()
//返回值:"1": 微信"; 2": QQ; 其他值: 未知
1
2

# 实时获取当前的网络状态

customBrowserInterface.getNetworkType()
//返回值: "NO NETWORK"、"WIFI"、"4G"、"3G"、"2G"、"UNKNOWN NETWORK"
1
2

# 当前的操作系统

customBrowserInterface.isAndroid()
//返回值:"1": Android; "0": iOS
1
2

# 关闭浏览器返回游戏

customBrowserInterface.closeWebview()
1

# 查看设备信息

customBrowserInterface.getDeviceInfo()
/*返回值:
  Android下的返回值: '{"osSystem":"", "osVersion":"", "deviceModel":"", "deviceName":"", "deviceTradeMark":"", "deviceManufacturer":"", "uid":"", "memoryUpperLimit":进程的内存上限(单位为K), "usedMemory":当前进程占用内存(单位为K), "processCpuTime":当前进程占用的CPU时间, "totalCpuTime":总的CPU时间, "dalvikMemory":Java代码占用的内存(单位为K), "nativeMemory":C/C++代码占用的内存(单位为K), "otherMemory":其他内存(单位为K)}'
  iOS下的返回值: '{"osSystem":"", "osVersion":"", "deviceModel":"", "uid":"", "deviceName":"", "physicalMemory":手机总的内存(单位为K), "usedMemory":当前进程占用内存(单位为K), "cpuUsageRatio":当前进程的CPU使用率(不带百分号的数值,如:3.1表示3.1%)}'
  注:返回值是JSON格式的字符串,iOS下在UIWebView中频繁调用此接口会导致内存飙升,WKWebView无此问题
  【1】Android下当"usedMemory + 新分配的内存 ≥ memoryUpperLimit"就会出现OOM(out of memory),iOS下当"usedMemory / physicalMemory ≥ 百分比值(不同系统这个值不一样)"时进程会被杀死,参考文献"https://stackoverflow.com/questions/5887248/ios-app-maximum-memory-budget"
  【2】Android下的CPU使用率 = (这次获取的processCpuTime - 上次获取的processCpuTime) / (这次获取的totalCpuTime - 上次获取的totalCpuTime)
*/
1
2
3
4
5
6
7
8

# 生成快捷方式

// Android下的调用方式:
customBrowserInterface.addShortcut(name, imgUrl, url)

// iOS下的调用方式:
customBrowserInterface.addShortcut(url)
// 注:name是快捷方式的名称,imgUrl是快捷方式的图标的url,Android下的url是快捷方式跳转的链接地址,iOS下的url是获取mobileconfig文件的链接地址。
// iOS下生成快捷方式是用Safari加载mobileconfig文件,根据mobileconfig文件进行安装,安装完毕就生成了快捷方式。
// Android下生成快捷方式不同于iOS,无需安装,但不一定会成功,部分手机禁止生成快捷方式,部分手机会被手机管家阻止,需要通过手机管家里的权限管理进行配置
1
2
3
4
5
6
7
8

# 上传图片

customBrowserInterface.imagePicker()
/*
	返回图片的base64编码,图片的格式为JPEG,为了防止占用太多内存,会对图片进行压缩(尺寸不变,存储空间变小),如果没有选择任何图片就会返回空串""
	使用demo:
		<img id="iosImg" height="200" width="200" />
		document.getElementById("iosImg").src = "data:image/jpeg;base64," + customBrowserInterface.imagePicker();
*/
1
2
3
4
5
6
7

# RSA 非对称加密

// 客户端只知道公钥,服务端只知道私钥
//【1】用公钥加密客户端的请求
var publicKey =
  '-----BEGIN PUBLIC KEY-----\n' +
  'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDzgSvQ4btonPCt1IOalue2N6i4\n' +
  'ABozjeC1rmmAY/ZcafPXsoafoTSgiJ1chF9ZQ/4Woc7eEkcTboenIiD58CjiFYfm\n' +
  'g05fZm3uqCpTT6Ht3qUhkEBS9PzjgP96gjUJ18am+m+jUzkABF7ow1EEmoaK4Q20\n' +
  'leneGrOt4uw+tJRbOwIDAQAB\n' +
  '-----END PUBLIC KEY-----'
var encrypted = customBrowserInterface.encrypt('客户端的请求', publicKey)
//【2】用公钥解密服务端的响应
var decrypted = customBrowserInterface.decrypt(
  '用私钥加密的服务端响应',
  publicKey
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 微信委托授权(.qq.com 下的页面才允许拉起微信委托授权)

// 微社区接入论坛时,为了打通各游戏的论坛帐号,需要将游戏的openid转换成论坛的openid,前提是需要拉起微信委托授权
customBrowserInterface.delegateLogin(游戏的微信Appid)
// 注意:如果在原生代码里传递了游戏的微信Appid,delegateLogin函数传递的微信Appid就会被忽略
1
2
3

# H5 页面给游戏发消息(需要游戏配合)

customBrowserInterface.sendToGame('XXX')
1

# 是否支持腾讯视频 SDK 高清播放器

customBrowserInterface.supportVideoPlayer();
返回值:
  "1": 支持
  "0": 不支持
1
2
3
4

# 利用腾讯视频 SDK 高清播放器全屏播放

if (
  'object' == typeof customBrowserInterface &&
  '1' == customBrowserInterface.supportVideoPlayer()
) {
  if ('0' == customBrowserInterface.fullScreenPlay(vid, title))
    alert('不支持腾讯视频SDK高清播放器,请使用video标签播放')
} else alert('不支持腾讯视频SDK高清播放器,请使用video标签播放')
1
2
3
4
5
6
7

# 利用腾讯视频 SDK 高清播放器在指定位置播放

if (
  'object' == typeof customBrowserInterface &&
  '1' == customBrowserInterface.supportVideoPlayer()
) {
  var offset = $('#videoImage').offset() /*封面图的绝对位置*/
  if (
    '0' ==
    customBrowserInterface.customPlay(
      vid,
      title,
      offset.left,
      offset.top,
      offset.width,
      offset.height
    )
  )
    alert('不支持腾讯视频SDK高清播放器,请使用video标签播放')
} else alert('不支持腾讯视频SDK高清播放器,请使用video标签播放')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 网页的尺寸发生变化时重新调整播放器的位置,可监听 onresize 事件,如:onresize="onresize()"

if (
  'object' == typeof customBrowserInterface &&
  '1' == customBrowserInterface.supportVideoPlayer()
) {
  var offset = $('#videoImage').offset() /*封面图的绝对位置*/
  customBrowserInterface.resizeCustomPlayer(
    offset.left,
    offset.top,
    offset.width,
    offset.height
  )
}
1
2
3
4
5
6
7
8
9
10
11
12

# 销毁视频播放器

if (
  'object' == typeof customBrowserInterface &&
  '1' == customBrowserInterface.supportVideoPlayer()
) {
  customBrowserInterface.hideVideoPlayer()
}
1
2
3
4
5
6

# 页面打开微信小程序

//id:  小程序id , path: 小程序对应页面路径
customBrowserInterface.openMiniProgram(id, path)
1
2