我试图用iPhone应用程序打到websocket连接.当我连接到ws:// localhost:3000 / cable时,我可以收到ping,但是我不太确定如何从JavaScript上下文中订阅频道.
解决方法
过了一会儿,我终于发现了这个神奇的Github问题页面:
https://github.com/rails/rails/issues/22675
I do understand that this patch would break some tests. That is not
surprising to me. But the original issue I believe is still relevant
and shouldn’t be closed.The following JSON sent to the server should succeed:
{“command”: “subscribe”,”identifier”:{“channel”:”ChangesChannel”}}
It does not! Instead you must send this:
{“command”:
“subscribe”,”identifier”:”{\”channel\”:\”ChangesChannel\”}”}
我终于得到了iOS应用程序订阅房间频道,按照Github用户对Rails问题的建议.
我的设置如下:
目标C
>使用PocketSocket框架进行Web套接字连接
> Rails 5 RC1
> Ruby 2.2.4p230
我假设你知道如何使用Cocoapods来安装PocketSocket.
相关规范如下:
ViewController.h
#import <PocketSocket/PSWebSocket.h> @interface ViewController : UIViewController <PSWebSocketDelegate,UITableViewDelegate,UITableViewDataSource,UITextFieldDelegate> @property (nonatomic,strong) PSWebSocket *socket;
ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view,typically from a nib. [self initViews]; [self initConstraints]; [self initSocket]; } -(void)initSocket { NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://localhost:3000/cable"]]; self.socket = [PSWebSocket clientSocketWithRequest:request]; self.socket.delegate = self; [self.socket open]; } -(void)joinChannel:(NSString *)channelName { NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }"; id data = @{ @"command": @"subscribe",@"identifier": strChannel }; NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil]; NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"myString= %@",myString); [self.socket send:myString]; } #pragma mark - PSWebSocketDelegate Methods - -(void)webSocketDidOpen:(PSWebSocket *)webSocket { NSLog(@"The websocket handshake completed and is now open!"); [self joinChannel:@"RoomChannel"]; } -(void)webSocket:(PSWebSocket *)webSocket didReceiveMessage:(id)message { NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSString *messageType = json[@"type"]; if(![messageType isEqualToString:@"ping"] && ![messageType isEqualToString:@"welcome"]) { NSLog(@"The websocket received a message: %@",json[@"message"]); [self.messages addObject:json[@"message"]]; [self.tableView reloadData]; } } -(void)webSocket:(PSWebSocket *)webSocket didFailWithError:(NSError *)error { NSLog(@"The websocket handshake/connection Failed with an error: %@",error); } -(void)webSocket:(PSWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean { NSLog(@"The websocket closed with code: %@,reason: %@,wasClean: %@",@(code),reason,(wasClean) ? @"YES": @"NO"); }
重要的提示:
def add(data) id_key = data['identifier'] id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access subscription_klass = connection.server.channel_classes[id_options[:channel]] if subscription_klass subscriptions[id_key] ||= subscription_klass.new(connection,id_key,id_options) else logger.error "Subscription class not found (#{data.inspect})" end end
注意行:
connection.server.channel_classes[id_options[:channel]]
我们需要使用该通道的类名.
DHH YouTube视频使用“room_channel”作为房间名称,但该频道的类文件名为“RoomChannel”.
发送消息
为了防止别人想知道如何发送消息,这里是我的iOS代码向服务器发送消息:
-(void)sendMessage:(NSString *)message { NSString *strMessage = [[NSString alloc] initWithFormat:@"{ \"action\": \"speak\",\"message\": \"%@\" }",message]; NSString *strChannel = @"{ \"channel\": \"RoomChannel\" }"; id data = @{ @"command": @"message",@"identifier": strChannel,@"data": strMessage }; NSData * jsonData = [NSJSONSerialization dataWithJSONObject:data options:0 error:nil]; NSString * myString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSLog(@"myString= %@",myString); [self.socket send:myString]; }
这假定您已经连接了您的UITextField来处理按住返回键或某些“发送”按钮的UI.
这个整个演示应用程序是一个快速的黑客,显然,如果我要在一个真正的应用程序中,我会使我的代码更干净,更可重用,并将其抽象为一个类.
从真正的iPhone设备连接到Rails服务器:
为了iPhone应用程序可以在实际的设备上与Rails服务器通话,而不是iPhone模拟器.
执行以下操作:
检查您的计算机的TCP / IP地址.例如,在我的iMac上,有些日子可能是10.1.1.10(如果使用DHCP,将来可能会自动更改).
>编辑您的Rail的配置>环境> development.rb文件放在以下行之前的某个地方,如end关键字之前:
Rails.application.config.action_cable.allowed_request_origins = [‘http://10.1.1.10:3000’]
>使用以下命令启动Rails服务器:
rails server -b 0.0.0.0
>构建并运行您的iPhone应用程序到iPhone设备上.您现在应该可以连接和发送消息:D
Request origin not allowed: http://localhost:3001 when using Rails5 and ActionCable
Rails 4.2 server; private and public ip not working
希望能在未来帮助别人.