Skip to content

Instantly share code, notes, and snippets.

@daleffe
Created December 7, 2022 22:50
Show Gist options
  • Save daleffe/b0f5e977fca3a82f7a9e722bd304241c to your computer and use it in GitHub Desktop.
Save daleffe/b0f5e977fca3a82f7a9e722bd304241c to your computer and use it in GitHub Desktop.
Sockets for Ionic Cordova

Any way to help with a ionic 4/5 integration using this... I am struggling to get the var declare Socket:any setup to work in Ionic 4/5

Hi @Burnie777, i will reproduce some parts of code of production app that works to help you.

  1. The socket service

Here we created a service with following content, transforming the Cordova events in Observables:

import { Injectable } from '@angular/core';
import { Platform } from '@ionic/angular';

import { Observable } from 'rxjs';

import { ConverterProvider } from './../providers/converter.provider';

@Injectable({
  providedIn: 'root'
})
export class SocketService {
  tcp: any;

  constructor(private platform: Platform, private converter: ConverterProvider) { 
    this.platform.ready().then(() => {      
      this.tcp = new (<any>window).Socket();
    });    
  }

  init() {
    this.tcp = new (<any>window).Socket();
  }

  events() {    
    return new Observable(observer => {
      this.tcp.onData = asData => observer.next('socket.onData|' + this.converter.arrayBuffer2str(asData));

      this.tcp.onError = asError => observer.next('socket.onError|' + JSON.stringify(asError));

      this.tcp.onClose = asClose => observer.error('socket.onClose|' + asClose);      
    });
  }  
}
  1. Converter helper

We created a provider with converter functions:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ConverterProvider {

  constructor() { }

  arrayBuffer2str(buf: Uint8Array) {
    return String.fromCharCode.apply(null, new Uint16Array(buf));
  }

  Str2ArrayBuffer(dataString: string) {
    let data = new Uint8Array(dataString.length);
    for (let i = 0; i < data.length; i++) {
      data[i] = dataString.charCodeAt(i);
    }
    return data;
  }
}
  1. Putting it to work

Finally we are able to use sockets! Below is an example of how to implement it on your foo.page.ts (some parts of code ommited):

import { Component, OnInit, ViewChild, NgZone } from '@angular/core';

import { ConverterProvider } from './../../providers/converter.provider';

import { SocketService } from './../../services/socket.service';

constructor(private ngZone: NgZone, private converter: ConverterProvider, private socket: SocketService) {}

private open(device: DeviceModel) {
    this.socket.init();

    this.socket.tcp.open(device.address, device.netPortConfig,
      () => {
        this.ngZone.run(() => {
          this.setDeviceState(true);

          console.log(`[Socket] New connection: ${device.address} (${device.name})`);

          this.message.popUp(`${device.name} connected`);
        });

        this.socket.events().subscribe(
          data => {
            let split = data.toString().split('|');

            if (split[0].toLowerCase().trim().includes('socket.onerror')) {
              this.ngZone.run(() => console.warn(`[Socket] Connection error:`, JSON.parse(split[1].trim())));
            } else {
              let received = split[1].trim();
              console.log('Received data: ', received);
            }
          },
          error => {
            this.ngZone.run(() => {
              this.message.popUp(`Device was disconnected`);
              
              this.setDeviceState(false);

              console.error('[Socket] Connection closed:', error);
            });
          }
        );        

        this.socket.tcp.write(
          this.converter.Str2ArrayBuffer('Hello World!'),
          () => {
            this.ngZone.run(() => {
              console.log(`[Socket] Data successfully sent to ${device.address} (${device.name})`);
            });
          }, error => {
            this.ngZone.run(() => {
              console.error(`[Socket] Unable to sent data to ${device.address} (${device.name})`, error);
            });
          }
        )
      }, (error: string) => {
        this.ngZone.run(() => {
          this.setDeviceState(false);          
          
          console.error(`[Socket] Unable to connect: ${device.address} (${device.name}) `, error);
          this.message.popUp(`Unable to connect: ${device.name}`);
        });
      }
    );
  }

You can now create a button by calling the open method and passing the settings of the server (which I called the device) you want to connect.

Some notes:

  • The Device parameter in open method has the connection configs (host address, network port, etc);
  • We created the method init() in socket service because when you reuse the object a lot of times it crashes plugin, then we "init" every new connection;
  • NgZone is used to properly update interface/visual elements (i just left the console.log for example).

Hope it helps, if you have any problems, just point out that we help (I screwed up a lot until it worked correctly).

I'll create an example project this week to help then update here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment