一、SignalR介绍

  SignalR是微软基于.Net提供的一个开源实时Web RPC库,可以用在web实时通信的需求上面,比如聊天,web数据更新

  SignalR的接口使用十分简单

  由于最近的一个需求需要调研RPC库,偶然看到github上面一份在iOS上面使用SignalR 客户端请求的代码

  下面对代码有意思的地方进行一下分析

二、专门去搜了一下,github上面存在一份400+赞的SignalR native代码,应该可以使用;

  除此之外,工程代码:https://github.com/adamhartford/SwiftR 提供了另外一种方式

  signalR在web上面应用比较成熟,因此jQuery上面有对应的lib,

  这一份工程也是使用一个webview,运行本地的html文件,使用jQuery的signalR库,然后注入一段js,这段js跟本地app桥接通信

   

  html文件:

<html>
<head></head>
<body>
"
<script src="\'file:///private/var/mobile/Containers/Data/Application/C5176D20-0015-4DFB-9156-D53DB6544F3E/tmp/SwiftR/jquery-2.1.3.min.js\'"></script>
<script src="\'file:///private/var/mobile/Containers/Data/Application/C5176D20-0015-4DFB-9156-D53DB6544F3E/tmp/SwiftR/jquery.signalr-2.2.0.min\'"></script>
<script src="\'file:///private/var/mobile/Containers/Data/Application/C5176D20-0015-4DFB-9156-D53DB6544F3E/tmp/SwiftR/SwiftR.js\'"></script>"
</body>
</html>

  可以看到引用了三个js文件,其中上面的库是本地打包的;根据版本进行选择

  

  打包的js中 SwiftR.js ,调用signalR库,同时和本地通信

  

window.swiftR = {
connection: null,
hubs: {},
transport: 'auto',
headers: {},
messages: {}
}; $(function() {
$.ajaxSetup({
beforeSend: function (jqxhr) {
for (var h in swiftR.headers) {
jqxhr.setRequestHeader(h, swiftR.headers[h]);
}
}
});
postMessage({ message: 'ready' });
}); function initialize(baseUrl, isHub) {
swiftR.connection = isHub ? $.hubConnection(baseUrl) : $.connection(baseUrl);
var connection = swiftR.connection; connection.logging = true; if (!isHub) {
connection.received(function(data) {
postMessage({ data: data });
});
} connection.starting(function() {
postMessage({ message: 'starting' });
}); connection.connectionSlow(function() {
postMessage({ message: 'connectionSlow' });
}); connection.reconnecting(function() {
postMessage({ message: 'reconnecting' });
}); connection.reconnected(function() {
postMessage({ message: 'reconnected' });
}); connection.disconnected(function () {
postMessage({ message: 'disconnected' });
}); connection.error(function(error) {
postMessage({ message: 'error', error: processError(error) });
});
} function start() {
swiftR.connection.start({ transport: swiftR.transport }).done(function() {
postMessage({ message: 'connected', connectionId: swiftR.connection.id });
}).fail(function() {
postMessage({ message: 'connectionFailed' });
});
} function addHandler(id, hubName, method) {
var hub = ensureHub(hubName); hub.on(method, function() {
postMessage({
id: id,
hub: hub.hubName,
method: method,
arguments: [].slice.call(arguments)
});
});
} function postMessage(msg) {
var id = Math.random().toString(36).slice(2, 10);
swiftR.messages[id] = msg; if (window.webkit) {
webkit.messageHandlers.interOp.postMessage(id);
} else {
var frame = $('<iframe/>', { src: 'swiftr://' + id });
$('body').append(frame);
frame.remove();
}
} function ensureHub(name) {
var hub = swiftR.hubs[name]; if (!hub) {
hub = swiftR.connection.createHubProxy(name);
swiftR.hubs[name] = hub;
} return hub;
} function processError(error) {
var err = {
message: error.message || 'An unknown error has occurred.'
} if (typeof error.source === 'string') {
err.source = error.source;
} return err;
} function readMessage(id) {
var msg = swiftR.messages[id];
delete swiftR.messages[id];
return window.webkit ? msg : JSON.stringify(msg);
}

  其中下面的函数,可以通过webview的接口直接调用。

function start() {
swiftR.connection.start({ transport: swiftR.transport }).done(function() {
postMessage({ message: 'connected', connectionId: swiftR.connection.id });
}).fail(function() {
postMessage({ message: 'connectionFailed' });
});
} function addHandler(id, hubName, method) {
var hub = ensureHub(hubName); hub.on(method, function() {
postMessage({
id: id,
hub: hub.hubName,
method: method,
arguments: [].slice.call(arguments)
});
});
}

  当有了回调信息之后,js可以通过下面的方法直接返回

function postMessage(msg) {
var id = Math.random().toString(36).slice(2, 10);
swiftR.messages[id] = msg; if (window.webkit) {
webkit.messageHandlers.interOp.postMessage(id);
} else {
var frame = $('<iframe/>', { src: 'swiftr://' + id });
$('body').append(frame);
frame.remove();
}
}

  在原生代码这边,通过下面的方法主动调用js

    func runJavaScript(_ script: String, callback: ((Any?) -> ())? = nil) {
guard wkWebView != nil || webView != nil else {
jsQueue.append((script, callback))
return
} if useWKWebView {
wkWebView.evaluateJavaScript(script, completionHandler: { (result, _) in
callback?(result)
})
} else {
let result = webView.stringByEvaluatingJavaScript(from: script)
callback?(result as AnyObject!)
}
}

  js的消息通过下面的代码回调 WKScriptMessageHandler 机制

    open func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let id = message.body as? String {
wkWebView.evaluateJavaScript("readMessage('\(id)')", completionHandler: { [weak self] (msg, err) in
if let m = msg as? [String: Any] {
self?.processMessage(m)
} else if let e = err {
print("SwiftR unable to process message \(id): \(e)")
} else {
print("SwiftR unable to process message \(id)")
}
})
}
}

  

三、总结

  实际使用验证了一下,看起来还比较稳定

  这个工程给我的思路是,可以借鉴web上的解决方案为app服务,不需要局限在iOS开发的范围上。

四、附录

  关于原生和js通信的方式:

  https://www.jianshu.com/p/433e59c5a9eb

    

iOS使用SignalR客户端代码典范-桥接web SignalR 客户端库的更多相关文章

  1. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十六节--SignalR与ABP框架Abp.Web.SignalR及扩展

    SignalR简介 SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...

  2. SignalR 实现web浏览器客户端与服务端的推送功能

    SignalR 是一个集成的客户端与服务器库,基于浏览器的客户端和基于 ASP.NET 的服务器组件可以借助它来进行双向多步对话. 换句话说,该对话可不受限制地进行单个无状态请求/响应数据交换:它将继 ...

  3. 【SignalR学习系列】7. SignalR Hubs Api 详解(JavaScript 客户端)

    SignalR 的 generated proxy 服务端 public class ContosoChatHub : Hub { public void NewContosoChatMessage( ...

  4. 使用ASP.NET MVC Web SignalR 构建单身聊天室(一)

    前言:本系列的头章,想要带大家一起学习Web SignalR,那它是什么呢?ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.什么 ...

  5. 比官方教程代码更简短的SignalR Server Broadcast示例

    SignalR是微软ASP.NET技术体系中的新成员. 在www.asp.net网站上的SignalR专区有一篇SignalR的入门级教程<Tutorial: Server Broadcast  ...

  6. 在C#开发中如何使用Client Object Model客户端代码获得SharePoint 网站、列表的权限情况

    自从人类学会了使用火,烤制的方式替代了人类的消化系统部分功能,从此人类的消化系统更加简单,加速了人脑的进化:自从SharePoint 2010开始有了Client Side Object Model ...

  7. iOS流行的开源代码库

    本文介绍一些流行的iOS的开源代码库 1.AFNetworking 更新频率高的轻量级的第三方网络库,基于NSURL和NSOperation,支持iOS和OSX.https://github.com/ ...

  8. 使用Myeclipse插件将wsdl生成java客户端代码

    使用环境:MyEclipse9.0 本教程使用Myeclipse内置插件生成java代码,网上说这是xfire插件,不管怎样,生成和调用客户端代码都十分简单. 1.在项目上右键,选择New->O ...

  9. 初学svn对版本进行控制 用post- commit钩子实现代码同步到web目录

    这里只是一个记录,原文摘抄svn利用钩子实现代码同步到web目录 思路: 找 到SVN Server中的仓库(Repositories)文件夹的位置,在相应的项目文件夹中找到hooks文件夹.在该文件 ...

  10. webservice 服务端例子+客户端例子+CXF整合spring服务端测试+生成wsdl文件 +cxf客户端代码自动生成

    首先到CXF官网及spring官网下载相关jar架包,这个不多说.webservice是干嘛用的也不多说. 入门例子 模拟新增一个用户,并返回新增结果,成功还是失败. 大概的目录如上,很简单. Res ...

随机推荐

  1. 【未测试】CentOS 6.5快速部署HTTP WEB服务器和FTP服务器

    CentOS 6.5快速部署HTTP WEB服务器和FTP服务器 [题记]本文使用CentOS 6.5minimal快速搭建HTTP服务器和仅供授权用户登陆的FTP服务器.意在使用授权FTP用户通过登 ...

  2. 重新整理linux 系列 ——硬件的介绍(一)

    前言 打算重新整理linux,计划每天一更,希望能够按照计划执行吧. 正文 首先有一个疑惑,那就是一台手机是否是一台计算机? 来看下什么可以定义为一台计算机: 计算机为接收用户的输入,经由中央处理器的 ...

  3. 力扣238(java)-除自身以外数组的乘积(中等)

    题目: 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 . 题目数据 保证 数组 nums之中任意元素的全 ...

  4. 一文搞懂传统单节点网站的 Serverless 上云

    简介: 阿里云函数计算 FC 是事件驱动的全托管计算服务,真正的无需去考虑服务器的运维管理,只需要完成开发的代码进行上传,函数计算会通过角色策略去规划计算资源,弹性的方式执行函数,最后高效的执行部署. ...

  5. 云原生DevOps的5步升级路径

    简介: 究竟什么是云原生DevOps呢?我们认为:云原生DevOps是充分利用云原生基础设施,基于微服务/无服务架构体系和开源标准,语言和框架无关,具备持续交付和智能自运维能力,从而做到比传统DevO ...

  6. 【实践案例】Databricks 数据洞察 Delta Lake 在基智科技(STEPONE)的应用实践

    简介: 获取更详细的 Databricks 数据洞察相关信息,可至产品详情页查看:https://www.aliyun.com/product/bigdata/spark 作者 高爽,基智科技数据中心 ...

  7. [FAQ] uni-app 不支持 v-cloak 情况下如何处理 v-if 页面闪烁问题

    在 Vue 中存在使用 v-if 决定元素显示隐藏的时候,会出现页面闪烁,那么当然 uni-app 中也存在了. 如果编译完后,需要满足 js 的某个条件才隐藏,页面元素必然会有闪烁的情况. 所以解决 ...

  8. dotnet 将控制台 Console.WriteLine 内容输出到文件

    很多伙伴喜欢使用 Console.WriteLine 打日志,也许是打起来顺手.打完了之后,又想着,要是能够输出到本机文件那就更好了.既然很多伙伴都有这个想法,那 dotnet 自然就是有方便的方法让 ...

  9. dotnet CBB 为什么决定推送 Tag 才能打包

    通过推送 Tag 才打 NuGet 包的方法的作用不仅仅是让打包方便,让打包这个动作可以完全在本地执行,无需关注其他系统的使用步骤.更重要的是可以强制每个可能被安装的 NuGet 包版本都能有一个和他 ...

  10. Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/xxx". at createRouterError 的说明和解决

    错误说明 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: & ...