ruby-on-rails – 从iOS应用程序连接到ActionCable

我一整天都被困在这里.我有一个非常简单的ActionCable示例应用程序(聊天应用程序)由David Heinemeier Hansson正常工作( https://www.youtube.com/watch?v=n0WUjGkDFS0).

我试图用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

希望能在未来帮助别人.

相关文章

validates:conclusion,:presence=>true,:inclusion=>{...
一、redis集群搭建redis3.0以前,提供了Sentinel工具来监控各...
分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣...
上一篇博文 ruby传参之引用类型 里边定义了一个方法名 mo...
一编程与编程语言 什么是编程语言? 能够被计算机所识别的表...
Ruby类和对象Ruby是一种完美的面向对象编程语言。面向对象编...