Giter Site home page Giter Site logo

chinloyal / pusher_client Goto Github PK

View Code? Open in Web Editor NEW
42.0 4.0 164.0 116 KB

A Pusher Channels Client for Fluttter (Fully supports Android and iOS)

Home Page: https://pusher.com/channels

License: MIT License

Kotlin 35.05% Ruby 3.63% Swift 26.78% Objective-C 1.06% Dart 33.49%
flutter pusher pusher-channels chat flutter-plugin flutter-package pusher-client connection-socket events-triggered

pusher_client's Introduction

Pusher Channels Flutter Client

pub version GitHub license Languages Twitter

A Pusher Channels client plugin for Flutter targeting Android and iOS. It wraps pusher-websocket-java v2.2.5 and pusher-websocket-swift v8.0.0.

For tutorials and more in-depth information about Pusher Channels, visit the official docs.

This client works with official pusher servers and laravel self hosted pusher websocket server (laravel-websockets).

Supported Platforms & Deployment Targets

  • Android API 16 and above
  • iOS 9.0 and above

Table of Contents

Installation

Add to your pubspec.yaml

dependencies:
    pusher_client: ^2.0.0

Configuration

For iOS

Set the minimum deployment target in the Podfile to 9.0. Go to ios/Podfile, then uncomment this line:

# platform :ios, '8.0'

Change it to:

platform :ios, '9.0'

You may have an issue subscribing to private channels if you're using a local pusher server like laravel-websockets, to fix this go to ios/Runner/Info.plist and add:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

If you know which domains you will connect to add:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>example.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

For Android

If you have enabled code obfuscation with R8 or proguard, you need to add the following rule in android/app/build.gradle:

buildTypes {
  release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  }
}

Then in android/app/proguard-rules.pro:

-keep class com.github.chinloyal.pusher_client.** { *; }

API Overview

Here's the API in a nutshell.

PusherOptions options = PusherOptions(
    host: 'example.com',
    wsPort: 6001,
    encrypted: false,
    auth: PusherAuth(
        'http://example.com/auth',
        headers: {
            'Authorization': 'Bearer $token',
        },
    ),
);

PusherClient pusher = PusherClient(
    YOUR_APP_KEY,
    options,
    autoConnect: false
);

// connect at a later time than at instantiation.
pusher.connect();

pusher.onConnectionStateChange((state) {
    print("previousState: ${state.previousState}, currentState: ${state.currentState}");
});

pusher.onConnectionError((error) {
    print("error: ${error.message}");
});

// Subscribe to a private channel
Channel channel = pusher.subscribe("private-orders");

// Bind to listen for events called "order-status-updated" sent to "private-orders" channel
channel.bind("order-status-updated", (PusherEvent event) {
    print(event.data);
});

// Unsubscribe from channel
pusher.unsubscribe("private-orders");

// Disconnect from pusher service
pusher.disconnect();

More information in reference format can be found below.

The Pusher Constructor

The constructor takes an application key which you can get from the app's API Access section in the Pusher Channels dashboard, and a pusher options object.

PusherClient pusher = PusherClient(YOUR_APP_KEY, PusherOptions());

If you are going to use private, presence or encrypted channels then you will need to provide a PusherAuth to be used when authenticating subscriptions. In order to do this you need to pass in a PusherOptions object which has had an auth set.

PusherAuth auth = PusherAuth(
    // for auth endpoint use full url
    'http://example.com/auth',
    headers: {
        'Authorization': 'Bearer $token',
    },
);

PusherOptions options = PusherOptions(
    auth: auth
);

PusherClient pusher = PusherClient(YOUR_APP_KEY, options);

To disable logging and auto connect do this:

PusherClient pusher = PusherClient(
    YOUR_APP_KEY,
    options,
    enableLogging: false,
    autoConnect: false,
);

If auto connect is disabled then you can manually connect using connect() on the pusher instance.

Pusher Options Config

Most of the functionality of this plugin is configured through the PusherOptions object. You configure it by setting parameters on the object before passing it to the Pusher client. Below is a table containing all of the properties you can set.

Method Parameter Description
encrypted bool Whether the connection should be made with TLS or not.
auth PusherAuth Sets the authorization options to be used when authenticating private, private-encrypted and presence channels.
host String The host to which connections will be made.
wsPort int The port to which unencrypted connections will be made. Automatically set correctly.
wssPort int The port to which encrypted connections will be made. Automatically set correctly.
cluster String Sets the cluster the client will connect to, thereby setting the Host and Port correctly.
activityTimeout int The number of milliseconds of inactivity at which a "ping" will be triggered to check the connection. The default value is 120,000.
pongTimeout int The number of milliseconds the client waits to receive a "pong" response from the server before disconnecting. The default value is 30,000.
maxReconnectionAttempts int Number of reconnection attempts that will be made when pusher.connect() is called, after which the client will give up.
maxReconnectGapInSeconds int The delay in two reconnection extends exponentially (1, 2, 4, .. seconds) This property sets the maximum inbetween two reconnection attempts.

Reconnecting

The connect() method is also used to re-connect in case the connection has been lost, for example if a device loses reception. Note that the state of channel subscriptions and event bindings will be preserved while disconnected and re-negotiated with the server once a connection is re-established.

Disconnecting

pusher.disconnect();

After disconnection the PusherClient instance will release any internally allocated resources (threads and network connections)

Subscribing To Channels

Channels use the concept of channels as a way of subscribing to data. They are identified and subscribed to by a simple name. Events are bound to a channel and are also identified by name.

As mentioned above, channel subscriptions need only be registered once by the PusherClient instance. They are preserved across disconnection and re-established with the server on reconnect. They should NOT be re-registered. They may, however, be registered with a PusherClient instance before the first call to connect - they will be completed with the server as soon as a connection becomes available.

Public Channels

The default method for subscribing to a channel involves invoking the subscribe method of your client object:

Channel channel = pusher.subscribe("my-channel");

This returns a Channel object, which events can be bound to.

Private Channels

Private channels are created in exactly the same way as public channels, except that they reside in the 'private-' namespace. This means prefixing the channel name:

Channel privateChannel = pusher.subscribe("private-status-update");

Subscribing to private channels involves the client being authenticated. See The Pusher Constructor section for the authenticated channel example for more information.

Private Encrypted Channels

Similar to Private channels, you can also subscribe to a private encrypted channel. This plugin fully supports end-to-end encryption. This means that only you and your connected clients will be able to read your messages. Pusher cannot decrypt them. These channels must be prefixed with 'private-encrypted-'

Like with private channels, you must provide an authentication endpoint. That endpoint must be using a server client that supports end-to-end encryption. There is a demonstration endpoint to look at using nodejs.

Presence Channels

Presence channels are channels whose names are prefixed by 'presence-'. Presence channels also need to be authenticated.

Channel presenceChannel = pusher.subscribe("presence-another-channel");

Binding To Events

There are two types of events that occur on channel subscriptions.

  1. Protocol related events such as those triggered when a subscription succeeds, for example "pusher:subscription_succeeded"
  2. Application events that have been triggered by code within your app
Channel channel = pusher.subscribe("private-orders");

channel.bind("order-status-updated", (PusherEvent event) {
    print(event.data);
});

Callback Parameters

The callbacks you bind receive a PusherEvent:

Property Type Description
eventName String The name of the event.
channelName String The name of the channel that the event was triggered on. (Optional)
data String The data that was passed to trigger, encoded as a string. If you passed an object then that will have been serialized to a JSON string which you can parse as necessary. (Optional)
userId String The ID of the user who triggered the event. This is only available for client events triggered on presence channels. (Optional)

Unbind Channel Events

You can unbind from an event by doing:

channel.unbind("order-status-updated");

Triggering Client Events

Once a private or presence subscription has been authorized and the subscription has succeeded, it is possible to trigger events on those channels.

Events triggered by clients are called client events. Because they are being triggered from a client which may not be trusted there are a number of enforced rules when using them. Some of these rules include:

  • Event names must have a 'client-' prefix
  • Rate limits
  • You can only trigger an event when the subscription has succeeded
channel.bind("pusher:subscription_succeeded", (PusherEvent event) {
    channel.trigger("client-istyping", {"name": "Bob"});
});

For full details see the client events documentation.

Accessing The Connection Socket ID

Once connected you can access a unique identifier for the current client's connection. This is known as the socket Id. You can access the value once the connection has been established as follows:

String socketId = pusher.getSocketId();

For more information on how and why there is a socket Id see the documentation on authenticating users and excluding recipients.

Resolve Common Issues

iOS doesn't log when enableLogging is set to true

iOS logging doesn't seem to output to flutter console, however if you run the app from Xcode you should be able to see the logs.

Subscribing to private channels with iOS

If using a local pusher server but are unable to subscribe to a private channel then add this to your ios/Runner/Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

If you know which domains you will connect to add:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>example.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

pusher_client's People

Contributors

chinloyal avatar nizwar avatar spiritinlife avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

pusher_client's Issues

PlatformException(TRIGGER_ERROR, Cannot trigger event client-my-tracking because channel private-ride-138 is in SUBSCRIBE_SENT state

Hello, I am making a delivery application in which the delivery man must constantly broadcast his location, everything is fine until the delivery man goes through areas where he does not have a very good signal for mobile data and pusher stops sending events, for which I have this error:

PlatformException(TRIGGER_ERROR, Cannot trigger event client-my-tracking because channel private-ride-138 is in SUBSCRIBE_SENT state, java.lang.IllegalStateException: Cannot trigger event client-my-tracking because channel private-ride-138 is in SUBSCRIBE_SENT state at com.pusher.client.channel.impl.PrivateChannelImpl.trigger(PrivateChannelImpl.java:48) at com.github.chinloyal.pusher_client.pusher.PusherService.trigger(PusherService.kt:278) at com.github.chinloyal.pusher_client.pusher.PusherService.access$trigger(PusherService.kt:30) at com.github.chinloyal.pusher_client.pusher.PusherService$register$1.onMethodCall(PusherService.kt:60) at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262) at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:178) at io.flutter.embedding.engine.dart.DartMessenger.lambda$handleMessageFromDart$0$DartMessenger(DartMessenger.java:206) at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$6ZD

My question here is... how can I know the status of a channel? because in the documentation it only shows how to know the state of the pusher with pusher.onConnectionStateChange(), but this takes about 30 to 40 seconds to show in an emulator, or how can I know if my events are being sent correctly?

For example, I have this: when the distributor starts to move, I capture its location every 10 meters, which is why I ask about the connection status of the pusher:

`conectarPusher(userId) async {
await pusher.connect();
channel = pusher.subscribe('private-ride-$userId')
pusher.onConnectionStateChange((state) async {
pusherConnection = state?.currentState ?? 'DISCONNECTED';
print(
"--- CAMBIO DE ESTADO de: ${state?.previousState} a -> ${state?.currentState}");

      if (state?.currentState == 'CONNECTED') {
        canSendEvents = true;
      } else {
        canSendEvents = false;
      }
    });

}`

BackgroundLocation.getLocationUpdates((position) async { final positionRepartidor = { "latitude": position.latitude, "longitude": position.longitude }; if (canSendEvents) { channel.trigger('client-my-tracking', jsonEncode(positionRepartidor)); } else { print("No envio nada porque el pusher está desconectado"); } });

and this one is my Pusher options configuration:
PusherClient pusher = PusherClient( Enviroments.appKeyPusher, PusherOptions( cluster: 'us2', encrypted: true, auth: PusherAuth(Enviroments.authEndPointPusher)), autoConnect: false);

please 🙏 what should be the correct way to check the status of the channel, the pusher and the correct sending of events

Support for Flutter Web Version

I tested the app in the web version and found it does not have support for it. Any plans to add support for the web version in flutter?

auth not working

Steps to reproduce

I want to auth to

pusher = new PusherClient(
      "name",
      PusherOptions(
        // if local on android use 10.0.2.2
        host: "hostname",
        wsPort: 6001,
        wssPort: 6002,
        encrypted: true,
        auth: PusherAuth(
          "api/link/broadcasting/auth",
          headers: {
        
            HttpHeaders.authorizationHeader:
                "Bearer " + LocalStorage.getData(key: "TokenUserLoad"),
     
          },
        ),
      ),
      enableLogging: true,
    );

Expected behaviour

to access auth

Actual behaviour

not access auth android or ios

...

connect failed: ETIMEDOUT (Connection timed out)

Hello there,

This isn't a package error because the package is working in all devices except on a Xiaomi Redmi Note 7.

the 'onConnectionError' method catch this error:

message: An exception was thrown by the websocket
code: null
Exception: failed to connect to websockets.************.pt/2001:bc8:4700:2300::29:503 (port 443) from /:: (port 42860): connect failed: ETIMEDOUT (Connection timed out)

Anyone has faced the same problem? Any guess?

ABANDONNED PACKAGE?

Hello everyone,

this package seems abandonned to me. Am i correct in assuming this?

Chinloyal is not reachable and has not closed a ticket since august.

No implementation found for method init on channel com.github.chinloyal/pusher_client

Unhandled Exception: MissingPluginException(No implementation found for method init on channel com.github.chinloyal/pusher_client)
E/flutter ( 1715): #0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:154:7)
E/flutter ( 1715):
E/flutter ( 1715): #1 PusherClient._init (package:pusher_client/src/pusher/pusher_client.dart:61:5)
E/flutter ( 1715):
E/flutter ( 1715):

MissingPluginException

I have tested it on ios emulator 12 pro max

VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method init on channel com.github.chinloyal/pusher_client)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:157:7)

#1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:332:12)
#2 PusherClient._init (package:pusher_client/src/pusher/pusher_client.dart:61:20)
#3 new PusherClient (package:pusher_client/src/pusher/pusher_client.dart:52:16)
#4 _chatState.initState (package:adalah/screens/chat.dart:20:27)
#5 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4765:58)
#6 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
#7 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#8 Element.updateChild (package:flutter/src/widgets/framework.dart:3327:18)
#9 SingleChildRenderObjectElement.mount (package:fl<…>
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method connect on channel com.github.chinloyal/pusher_client)
#0 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:157:7)

#1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:332:12)
#2 PusherClient.connect (package:pusher_client/src/pusher/pusher_client.dart:92:20)
#3 _chatState.initState (package:adalah/screens/chat.dart:27:12)
#4 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4765:58)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4601:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3569:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:3327:18)
#8 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6118:14)
#9 Element.inflateWidget (package<…>

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.6, on macOS 11.2.3 20D91 darwin-x64, locale en-EG)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 12.4)
[!] Android Studio (version 4.1)
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] VS Code (version 1.52.1)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.

Pusher stuck in [CONNECTING] and produce a fatal exception.

Steps to reproduce

I use pusher_client: ^1.1.0 with laravel_echo: ^0.2.8
I Initialize PusherClient as the example
PusherOptions options = PusherOptions( host: '****-app.com', wssPort: 6001, wsPort: 6001, cluster: "mt1", ); PusherClient(appKey, options);

In initState I initialize my echo
echo = new Echo({ 'broadcaster': 'pusher', 'crsfToken': $accessToken, 'X-CSRF-TOKEN': $accessToken, 'authEndpoint': '/broadcasting/auth', 'key': appKey, 'wsHost': '****-app.com', 'wsPort': 6001, 'wssPort': 6001, 'forceTLS': true, 'disableStats': false, 'enabledTransports': ['ws', 'wss'], 'cluster': 'mt1', 'client': pusherClient, 'auth': { 'headers': { 'Authorization': 'Bearer $accessToken' } } });

Expected behavior

As an expected behavior it should at least connect to the socket and proceed through the [CONNECTING] message so I can connect to the channel.

Actual behavior

PusherClient stuck in [CONNECTING] and produce a fatal exception as follow

FATAL EXCEPTION: pusher-java-client eventQueue
E/AndroidRuntime( 5489): Process: com.**.****, PID: 5489
E/AndroidRuntime( 5489): java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter code
E/AndroidRuntime( 5489): at com.github.chinloyal.pusher_client.pusher.listeners.ConnectionListener.onError(Unknown Source:7)
E/AndroidRuntime( 5489): at com.pusher.client.connection.websocket.WebSocketConnection$5.run(WebSocketConnection.java:238)
E/AndroidRuntime( 5489): at com.pusher.client.util.Factory$1.run(Factory.java:119)
E/AndroidRuntime( 5489): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime( 5489): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime( 5489): at java.lang.Thread.run(Thread.java:919)

...

error when debugging in ios simulator (Arm64 LibSodium)

Hello everyone, I need help with this bug:
I get this error when trying to test a flutter app in an ios simulator projectpath/ios/Pods/Sodium/Sodium/libsodium/libsodium-ios.a(libsodium_la-aead_xchacha20poly1305.o), building for iOS Simulator, but linking in object file built for iOS, for architecture arm64
excluding the arm64 architecture I get this other one:
Undefined symbol: Sodium.SecretBox.open(authenticatedCipherText: [Swift.UInt8], secretKey: [Swift.UInt8], nonce: [Swift.UInt8]) -> [Swift.UInt8]?

[ON_ERROR]: message: App key abc-def-123 not in this cluster. Did you forget to specify the cluster 4001

I am using laravel websockets on backend, and testing device is iPhone

Code Sample

import 'package:laravel_echo/laravel_echo.dart';
import 'package:pusher_client/pusher_client.dart';


PusherOptions options = PusherOptions(
        // cluster: 'mt1',
        host: 'example.com',
        encrypted: true,
        wsPort: 6001,

        // auth: PusherAuth(
        //   AUTH_URL,
        //   headers: {
        //     'Authorization': 'Bearer $BEARER_TOKEN',
        //   },
        // ),
      );

      // Create pusher client
      PusherClient pusherClient = PusherClient(
        'abc-def-123',
        options,
        autoConnect: false,
        enableLogging: true,
      );

      // Create echo instance
      Echo echo = Echo(
        broadcaster: EchoBroadcasterType.Pusher,
        client: pusherClient,
      );

      // Listening public channel
      echo.channel('channel-name-3').listen('EventName', (e) {
        print(e);
      });

      // Accessing pusher instance
      echo.connector.pusher.onConnectionStateChange((state) {
        print(state!.currentState.toString());
      });

Errors in console

"D/PusherClientPlugin: Event stream cancelled."
"D/PusherClientPlugin: Event stream listening..."
"D/PusherClientPlugin: [connecting]"
"D/PusherClientPlugin: Subscribed: channel-name-3"
"D/PusherClientPlugin: Event stream cancelled."
"D/PusherClientPlugin: Event stream listening..."
"D/PusherClientPlugin: [BIND] App\Events\EventName"
flutter: connecting
[connection] nw_endpoint_handler_set_adaptive_read_handler [C17.1 52.71.241.74:443 ready socket-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for read_timeout failed
[connection] nw_endpoint_handler_set_adaptive_write_handler [C17.1 52.71.241.74:443 ready socket-flow (satisfied (Path is satisfied), viable, interface: en0, ipv4, dns)] unregister notification for write_timeout failed
"D/PusherClientPlugin: [ON_ERROR]: message: App key abc-def-123 not in this cluster. Did you forget to specify the cluster?, code: Optional(4001)"
"D/PusherClientPlugin: [disconnected]"
flutter: disconnectedWhat did you expect to happen?

Curiosity issue

I want to use the plugin on the android however host which is when on android local is 10.2.2.2 PusherOptions(
// if local on android use 10.0.2.2
host: '10.0.2.2',
encrypted: false,
)
should I change it when I publish my android app?

Keeps in connecting status in IOS

Flutter doctor:
`Doctor summary (to see all details, run flutter doctor -v):

[✓] Flutter (Channel stable, 3.3.4, on macOS 12.6 21G115 darwin-arm, locale en-PH)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 14.0)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.3)
[✓] VS Code (version 1.72.2)
[✓] Connected device (5 available)
[✓] HTTP Host Availability
`

Logs:

"D/PusherClientPlugin: Event stream listening..." "D/PusherClientPlugin: Pusher initialized" "D/PusherClientPlugin: [connecting]" "D/PusherClientPlugin: [connecting]" flutter: INFO: --> POST https://api.hours.fi/api/users/560/update_token flutter: INFO: content-type: application/json; charset=utf-8 flutter: INFO: {"token":""} flutter: INFO: --> END POST (175-byte body) flutter: INFO: --> GET https://api.hours.fi/api/notifications?page=1&is_paginate=true&per_page=10 flutter: INFO: --> END GET flutter: \^[[38;5;12m┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────<…> flutter: \^[[38;5;12m│ #0 _MainAppState.build.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:hours_flutter/main.dart:169:38)<…> flutter: \^[[38;5;12m│ #1 BlocBuilder.build (package:flutter_bloc/src/bloc_builder.dart:90:57)<…> flutter: \^[[38;5;12m├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄<…> flutter: \^[[38;5;12m│ 💡 AuthenticationState=Authenticated(false)<…> flutter: \^[[38;5;12m└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────<…> "D/PusherClientPlugin: Subscribed: user_560" "D/PusherClientPlugin: Event stream cancelled." "D/PusherClientPlugin: Event stream listening..." "D/PusherClientPlugin: [BIND] App\\Events\\WorkUpdate" "D/PusherClientPlugin: Subscribed: private-users_560" "D/PusherClientPlugin: Event stream cancelled." "D/PusherClientPlugin: Event stream listening..." "D/PusherClientPlugin: [BIND] Illuminate\\Notifications\\Events\\BroadcastNotificationCreated" flutter: \^[[38;5;12m┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────<…> flutter: \^[[38;5;12m│ #0 PusherClientHelper.initializePusherClient.<anonymous closure> (package:hours_flutter/src/api/pusher_client.dart:35:14)<…> flutter: \^[[38;5;12m│ #1 PusherClient._eventHandler (package:pusher_client/src/pusher/pusher_client.dart:127:34)<…> flutter: \^[[38;5;12m├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄<…> flutter: \^[[38;5;12m│ 💡 previousState: connecting, currentState: connecting<…> flutter: \^[[38;5;12m└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────<…>

I'm using physical device iPhone X iOS 15.6
Been stuck for 2 days. Any help or hind is appreciated. Thank you.

Android compilation error

When i try to run my project with this dependency pusher_channels_flutter: ^1.0.1
This error appears ->

/Users/julian/Documents/work/app/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java:144: error: cannot access ConnectionEventListener
      flutterEngine.getPlugins().add(new com.pusher.channels_flutter.PusherChannelsFlutterPlugin());
                                ^
  class file for com.pusher.client.connection.ConnectionEventListener not found
1 error

Error running on iOS

I cannot run on iOS due to this error

Uncategorized (Xcode): Command CompileSwiftSources failed with a nonzero exit code

Swift Compiler Error (Xcode): Could not find module 'PusherSwiftWithEncryption' for target 'arm64-apple-ios-simulator'; found: i386, x86_64-apple-ios-simulator, x86_64, i386-apple-ios-simulator, at: /Users/moataz/Projects/Transfer/build/ios/Debug-iphonesimulator/PusherSwiftWithEncryption/PusherSwiftWithEncryption.framework/Modules/PusherSwiftWithEncryption.swiftmodule
/Users/moataz/Development/flutter/.pub-cache/hosted/pub.dartlang.org/pusher_client-2.0.0/ios/Classes/AuthRequestBuilder.swift:7:7

and this is my podfile

# Uncomment this line to define a global platform for your project
platform :ios, '10.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
  'Debug' => :debug,
  'Profile' => :release,
  'Release' => :release,
}

def flutter_root
  generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
  unless File.exist?(generated_xcode_build_settings_path)
    raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
  end

  File.foreach(generated_xcode_build_settings_path) do |line|
    matches = line.match(/FLUTTER_ROOT\=(.*)/)
    return matches[1].strip if matches
  end
  raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end

  installer.pods_project.build_configurations.each do |config|
    config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
    config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
  end
end

I need help as I am stuck on this the whole day.
surely I tried many solutions mentioned on stackoverflow

Presence Channel Member Added / Member Removed on iOS.

Steps to reproduce

  • Install example app, setup Pusher presence channel.
  • Connect to Pusher presence channel
  • Bind to pusher:member_added / pusher:member_removed

Expected behavior

Member data returned when these two pusher events are bound.

Actual behavior

No response on iOS. Pusher SDK recommends passing onMemberAdded and onMemberRemoved callbacks when the presence channel is bound on iOS.

Any improvements you suggest

No it's a good package overall. Member added / member removed works on Android, but I would suggest transforming the data to a JSON payload. It comes as a Java List string and is difficult to parse. Here is how I parsed it:

channel.bind('pusher:subscription_succeeded', (members) {
    if(Platform.isAndroid) {
        var users = [];
        String str = members.data.toString();
        String regexString = r'(?<=\{)(.*?)(?=\})';
        RegExp regExp = new RegExp(regexString);
        var matches = regExp.allMatches(str);
        matches.forEach((element) {
        String jsonString = "{"+element.group(0)+"}";
        var user = jsonDecode(jsonString);
        print(user.toString());
        });
    } else {
        // ... IOS payload works fine.
    }
});

...

Can not connect private channels on iOS

I am trying to connect private channel but I keep getting this error:

Error authorizing channel [private-channel]: Optional("{\"success\":false,\"message\":\"\"}")
"D/PusherClientPlugin: [ON_EVENT] Channel: private-channel, EventName: pusher:subscription_error, Data: {\"success\":false,\"message\":\"\"}, User Id: "

Everything works fine on Android.

failed to connect to ip6-localhost/::1

{message: An exception was thrown by the websocket, code: null, exception: failed to connect to ip6-localhost/::1 (port 80) from /:: (port 45290): connect failed: ECONNREFUSED (Connection refused)}

I have a problem with channel trigger

E/PusherClientPlugin(17949): Reply already submitted
W/System.err(17949): java.lang.IllegalStateException: Reply already submitted
W/System.err(17949): 	at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:286)
W/System.err(17949): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.success(MethodChannel.java:267)
W/System.err(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService.trigger(PusherService.kt:288)
W/System.err(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService.access$trigger(PusherService.kt:30)
W/System.err(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService$register$1.onMethodCall(PusherService.kt:60)
W/System.err(17949): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
W/System.err(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:178)
W/System.err(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.lambda$handleMessageFromDart$0$DartMessenger(DartMessenger.java:206)
W/System.err(17949): 	at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$6ZD1MYkhaLxyPjtoFDxe45u43DI.run(Unknown Source:12)
W/System.err(17949): 	at android.os.Handler.handleCallback(Handler.java:938)
W/System.err(17949): 	at android.os.Handler.dispatchMessage(Handler.java:99)
W/System.err(17949): 	at android.os.Looper.loop(Looper.java:223)
W/System.err(17949): 	at android.app.ActivityThread.main(ActivityThread.java:7656)
W/System.err(17949): 	at java.lang.reflect.Method.invoke(Native Method)
W/System.err(17949): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
W/System.err(17949): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): Failed to handle method call
E/MethodChannel#com.github.chinloyal/pusher_client(17949): java.lang.IllegalStateException: Reply already submitted
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:286)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.error(MethodChannel.java:272)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService.trigger(PusherService.kt:292)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService.access$trigger(PusherService.kt:30)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at com.github.chinloyal.pusher_client.pusher.PusherService$register$1.onMethodCall(PusherService.kt:60)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:178)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.lambda$handleMessageFromDart$0$DartMessenger(DartMessenger.java:206)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$6ZD1MYkhaLxyPjtoFDxe45u43DI.run(Unknown Source:12)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at android.os.Handler.handleCallback(Handler.java:938)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at android.os.Looper.loop(Looper.java:223)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at android.app.ActivityThread.main(ActivityThread.java:7656)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
E/MethodChannel#com.github.chinloyal/pusher_client(17949): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
E/DartMessenger(17949): Uncaught exception in binary message listener
E/DartMessenger(17949): java.lang.IllegalStateException: Reply already submitted
E/DartMessenger(17949): 	at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:286)
E/DartMessenger(17949): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:282)
E/DartMessenger(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:178)
E/DartMessenger(17949): 	at io.flutter.embedding.engine.dart.DartMessenger.lambda$handleMessageFromDart$0$DartMessenger(DartMessenger.java:206)
E/DartMessenger(17949): 	at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$6ZD1MYkhaLxyPjtoFDxe45u43DI.run(Unknown Source:12)
E/DartMessenger(17949): 	at android.os.Handler.handleCallback(Handler.java:938)
E/DartMessenger(17949): 	at android.os.Handler.dispatchMessage(Handler.java:99)
E/DartMessenger(17949): 	at android.os.Looper.loop(Looper.java:223)
E/DartMessenger(17949): 	at android.app.ActivityThread.main(ActivityThread.java:7656)
E/DartMessenger(17949): 	at java.lang.reflect.Method.invoke(Native Method)
E/DartMessenger(17949): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
E/DartMessenger(17949): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
E/flutter (17949): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(TRIGGER_ERROR, Trigger can only be called on private and presence channels., null, null)
E/flutter (17949): #0      StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:607
E/flutter (17949): #1      MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:167
E/flutter (17949): <asynchronous suspension>
E/flutter (17949): #2      Channel.trigger
package:pusher_client/…/pusher/channel.dart:68
E/flutter (17949): <asynchronous suspension>
E/flutter (17949): #3      MapService.conectarPusher
package:repartidor_front_app/…/services/mapa_service.dart:35
E/flutter (17949): <asynchronous suspension>

when i try to do a channel.trigger i get this issues.
Asynchronous? I use "await" but it seems that its not the real issue, because in the before line: [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(TRIGGER_ERROR, Trigger can only be called on private and presence channels., null, null)
what am I doing wrong?
this is my code

PusherClient pusher = PusherClient(
      '******************',
      PusherOptions(
        cluster: 'us2',
        auth: PusherAuth(
            '------------------------------------'),
      ));
  late Channel channel;
conectarPusher() async {
    await pusher.connect();
    channel = pusher.subscribe("my-channel");
    print(channel.name);
    await channel.trigger('client-my-event', "Hello from APP");
    
}

Can't get it work using SSL

I'm getting this exception when trying to connect to private or presence channel.

W/System.err( 9862): com.pusher.client.AuthorizationFailureException: javax.net.ssl.SSLException: Unable to parse TLS packet header W/System.err( 9862): at com.pusher.client.util.HttpAuthorizer.authorize(HttpAuthorizer.java:146) W/System.err( 9862): at com.pusher.client.channel.impl.PrivateChannelImpl.getAuthResponse(PrivateChannelImpl.java:130) W/System.err( 9862): at com.pusher.client.channel.impl.PrivateChannelImpl.toSubscribeMessage(PrivateChannelImpl.java:90) W/System.err( 9862): at com.pusher.client.channel.impl.ChannelManager$1.run(ChannelManager.java:149) W/System.err( 9862): at com.pusher.client.util.Factory$1.run(Factory.java:119) W/System.err( 9862): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) W/System.err( 9862): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) W/System.err( 9862): at java.lang.Thread.run(Thread.java:923) W/System.err( 9862): Caused by: javax.net.ssl.SSLException: Unable to parse TLS packet header W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:807) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:747) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngine.unwrap(ConscryptEngine.java:712) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:849) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.access$100(ConscryptEngineSocket.java:722) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngineSocket.doHandshake(ConscryptEngineSocket.java:238) W/System.err( 9862): at com.android.org.conscrypt.ConscryptEngineSocket.startHandshake(ConscryptEngineSocket.java:217) W/System.err( 9862): at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:196) W/System.err( 9862): at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:153) W/System.err( 9862): at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116) W/System.err( 9862): at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186) W/System.err( 9862): at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) W/System.err( 9862): at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) W/System.err( 9862): at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) W/System.err( 9862): at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) W/System.err( 9862): at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465) W/System.err( 9862): at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131) W/System.err( 9862): at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:262) W/System.err( 9862): at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:219) W/System.err( 9862): at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:30) W/System.err( 9862): at com.pusher.client.util.HttpAuthorizer.authorize(HttpAuthorizer.java:122)

Double backslashes in the bind event breaks the JSON encoding.

First of all thanks a lot for this amazing library. I have been using this to trigger pusher client events and send over location data for a realtime map and it is working like a charm.

I am using this in conjuction with Laravel and most of the Laravel events are namespaced like this:

Illuminate\Notifications\Events\BroadcastNotificationCreated

I can try to escape the backslashes by escaping the backslashes with this format but this still breaks the JSON encoding.

Illuminate\\Notifications\\Events\\BroadcastNotificationCreated

In that case I get the message:

E/PusherClientPlugin(13562): Unterminated object at character 22 of {eventName=Illuminate\Notifications\Events\BroadcastNotificationCreated, channelName=orders}

Somehow at that point when binding the backslashes are removed again, what could be the case for this and is there a way to resolve this?

To reproduce you can simply subscribe to any channel and bind to a event like this:

Illuminate\\Notifications\\Events\\BroadcastNotificationCreated

When disconnecting the pusher got error

Hi, I'm using iPhone 12 Pro max (iOS 14.5) simulator to do testing. My simulator exit the app when i dismiss the page. My dispose included these 2 function pusher disconnect & Channel unbind. Here is the error message that debug console return to me. I've no idea what is the problem.

pusher_client/PusherService.swift:179: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Lost connection to device.

Android: Binding to channel events cancels calls to onConnectionStateChange etc

When binding to events on channels I receive no callbacks for onConnectionStateChange. If I don't bind to events I successfully receive callbacks.

It appears each bind adds a new listener to the EventChannel, however on the Android side each new listener replaces the previous PusherService.eventSink, so I assume that is why multiple listeners are not actually working.

Presence Channel Subscription in release mode crashes app

Steps to reproduce

Subscribe to a presence channel while the app is in release mode

Expected behavior

Crashes app
What did you expect to happen?

Actual behavior

What actually happened? Submit stack traces or anything that you think would help.

Any improvements you suggest

...

pusher keys implementation

I implemented 2 pusher keys in my project (1 from my main server, 1 from my inbox server).
But they're not work at the same time. Only one works.
Please help me with this issue.
Thanks in advantage !

Not receiving event when app is in pause IOS

Steps to reproduce

  1. Connect pusher client
  2. subscribe event
  3. screen lock device
  4. sent message
  5. Unlock device

Expected behavior

receive event if a device is locked

What did you expect to happen?
receive event if a device is locked

Actual behavior

not receiving events when a device is locked

What actually happened? Submit stack traces or anything that you think would help.

Any improvements you suggest

...

Receiving pusher:subscription_succeeded event twice

Steps to reproduce

Subscribe to the pusher:subscription_succeeded event, and you will get duplicate events.

_messageChannel.bind('pusher:subscription_succeeded', (PusherEvent? event) async {
          log('Subscription succeeded');
}

Logs

Subscription succeeded
Subscription succeeded

Expected behavior

We shouldn't be getting duplicate subscription succeeded events.

Triggering in public channel from flutter app

Triggering in private or presence app is described in the readme.
But triggering in public app is not described fully.
Also, some of my colleagues and flutter developers say it is not possible for this package to trigger event on public channel.
Is that true? (I hope not! 😊)

Please provide some examples or APIs of triggering events on public channels.
Thanks.

Incompatibility with connectivity plugin because of 'Reachability dependency/file' (iOS platform)

Steps to reproduce

in pubspec.yaml decalre poth flutter_pusher and connectivity plugins.

What did you expect to happen?

iOS build will fail. (Xcode build will somehow pass, but app won't be installed)

What actually happened? Submit stack traces or anything that you think would help.

The problem is some file/dependency named Reachability.
Another pusher plugin suffers the same problem: HomeX-It/pusher-websocket-flutter#11

...

Flutter + Laravel Websocket + Pusher Replacement (Valet Secure)

I'm using Beyondco Larevel Websockets on my Laravel Backend, and using pusher_client and laravel_echo on my Flutter frontend.

I've been trying to connect from my ios simulator into my Laravel Backend host, which is using valet secure, but failing.

My Flutter connections:


PusherClient getPusherClient(String token) {
  PusherOptions options = PusherOptions(
      host: 'my-local-server.test',
      wsPort: 6001,
      wssPort: 6001,
      cluster: DotEnv.env['PUSHER_APP_CLUSTER'],
      encrypted: true,
      auth: PusherAuth('https://my-local-server.test/api/broadcasting/auth',
          headers: {'Authorization': 'Bearer $token'})
  );

  return PusherClient(DotEnv.env['PUSHER_APP_KEY'], options,
      enableLogging: true, autoConnect: false);
}
pusherClient = getPusherClient(token);
pusherClient.connect();
pusherClient.onConnectionStateChange((state) {
  print(
      "previousState: ${state.previousState}, currentState: ${state.currentState}");
});
pusherClient.onConnectionError((error) {
  print(error.message);
});

From https://my-local-server.test/laravel-websockets I never see the requests from Flutter, but if I fire an event from my Laravel backend, it gets logged.

Please help me with what's wrong in my setup, why I can't connect to my SSL valet server running laravel-websocket from my Flutter application.

This package works with in Android but not in ios

I use pusher_client: ^2.0.0 it works without any problem with Android but when run my project on ios simulator I get error in the console.
when I run flutter run I get the following errors.


Xcode's output:
↳
    2 warnings generated.
    error: the following command failed with exit code 0 but produced no further output
    CompileC
    /Users/zia/Library/Developer/Xcode/DerivedData/Runner-hdzpmljlvwqzschdvjjsljzxqxtc/Build/Intermediates.noindex/
    Pods.build/Debug-iphonesimulator/location.build/Objects-normal/arm64/LocationPlugin.o
    /Users/zia/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/location-4.3.0/ios/Classes/LocationPlugin.m
    normal arm64 objective-c com.apple.compilers.llvm.clang.1_0.compiler (in target 'location' from project 'Pods')
    /Users/zia/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_phone_direct_caller-2.1.0/ios/Classes/F
    lutterPhoneDirectCallerPlugin.m:24:22: warning: 'stringByAddingPercentEscapesUsingEncoding:' is deprecated:
    first deprecated in iOS 9.0 - Use -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always
    uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each
    URL component or subcomponent has different rules for what characters are valid. [-Wdeprecated-declarations]
        number = [number stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                         ^
    In module 'UIKit' imported from /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Target Support
    Files/flutter_phone_direct_caller/flutter_phone_direct_caller-prefix.pch:2:
    In module 'Foundation' imported from
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:8:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURL.h:599:1: note:
    'stringByAddingPercentEscapesUsingEncoding:' has been explicitly marked deprecated here
    - (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc API_DEPRECATED("Use
    -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always uses the recommended UTF-8 encoding,
    and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has
    different rules for what characters are valid.", macos(10.0,10.11), ios(2.0,9.0), watchos(2.0,2.0),
    tvos(9.0,9.0));
    ^
    /Users/zia/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_phone_direct_caller-2.1.0/ios/Classes/F
    lutterPhoneDirectCallerPlugin.m:30:51: warning: 'openURL:' is deprecated: first deprecated in iOS 10.0
    [-Wdeprecated-declarations]
        } else if(![[UIApplication sharedApplication] openURL:[NSURL URLWithString:number]]) {
                                                      ^~~~~~~
                                                      openURL:options:completionHandler:
    In module 'UIKit' imported from /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Target Support
    Files/flutter_phone_direct_caller/flutter_phone_direct_caller-prefix.pch:2:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIApplication.h:124:1: note: 'openURL:' has been
    explicitly marked deprecated here
    - (BOOL)openURL:(NSURL*)url API_DEPRECATED_WITH_REPLACEMENT("openURL:options:completionHandler:", ios(2.0,
    10.0)) NS_EXTENSION_UNAVAILABLE_IOS("");
    ^
    2 warnings generated.
    /Users/zia/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_phone_direct_caller-2.1.0/ios/Classes/F
    lutterPhoneDirectCallerPlugin.m:24:22: warning: 'stringByAddingPercentEscapesUsingEncoding:' is deprecated:
    first deprecated in iOS 9.0 - Use -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always
    uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each
    URL component or subcomponent has different rules for what characters are valid. [-Wdeprecated-declarations]
        number = [number stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
                         ^
    In module 'UIKit' imported from /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Target Support
    Files/flutter_phone_direct_caller/flutter_phone_direct_caller-prefix.pch:2:
    In module 'Foundation' imported from
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIKit.h:8:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSURL.h:599:1: note:
    'stringByAddingPercentEscapesUsingEncoding:' has been explicitly marked deprecated here
    - (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc API_DEPRECATED("Use
    -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always uses the recommended UTF-8 encoding,
    and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has
    different rules for what characters are valid.", macos(10.0,10.11), ios(2.0,9.0), watchos(2.0,2.0),
    tvos(9.0,9.0));
    ^
    /Users/zia/Documents/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_phone_direct_caller-2.1.0/ios/Classes/F
    lutterPhoneDirectCallerPlugin.m:30:51: warning: 'openURL:' is deprecated: first deprecated in iOS 10.0
    [-Wdeprecated-declarations]
        } else if(![[UIApplication sharedApplication] openURL:[NSURL URLWithString:number]]) {
                                                      ^~~~~~~
                                                      openURL:options:completionHandler:
    In module 'UIKit' imported from /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Target Support
    Files/flutter_phone_direct_caller/flutter_phone_direct_caller-prefix.pch:2:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator15.
    2.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIApplication.h:124:1: note: 'openURL:' has been
    explicitly marked deprecated here
    - (BOOL)openURL:(NSURL*)url API_DEPRECATED_WITH_REPLACEMENT("openURL:options:completionHandler:", ios(2.0,
    10.0)) NS_EXTENSION_UNAVAILABLE_IOS("");
    ^
    2 warnings generated.
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:61:34:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketClient: class {
                                     ^~~~~
                                     AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:119:35:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WSStreamDelegate: class {
                                      ^~~~~
                                      AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:313:36:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketDelegate: class {
                                       ^~~~~
                                       AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:321:40:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketPongDelegate: class {
                                           ^~~~~
                                           AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:326:44:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketAdvancedDelegate: class {
                                               ^~~~~
                                               AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:282:30:
    warning: 'withUnsafeMutableBytes' is deprecated: use `withUnsafeMutableBytes<R>(_:
    (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R` instead
                let _ = peerName.withUnsafeMutableBytes { (peerNamePtr: UnsafeMutablePointer<Int8>) in
                                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1326:14:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1327:16:
    warning: 'init(bytes:)' is deprecated: use `init(_:)` instead
            return Data(bytes: digest).base64EncodedString()
                   ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:59:25:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
                            ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:29:
    warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                            
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:140:14:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:61:34:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketClient: class {
                                     ^~~~~
                                     AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:119:35:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WSStreamDelegate: class {
                                      ^~~~~
                         ...
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:282:30:
    warning: 'withUnsafeMutableBytes' is deprecated: use `withUnsafeMutableBytes<R>(_:
    (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R` instead
                let _ = peerName.withUnsafeMutableBytes { (peerNamePtr: UnsafeMutablePointer<Int8>) in
                                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1326:14:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1327:16:
    warning: 'init(bytes:)' is deprecated: use `init(_:)` instead
            return Data(bytes: digest).base64EncodedString()
                   ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:59:25:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
                            ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:29:
    warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57:
    note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid
    only for the duration of the call to 'init(_:)'
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^~~~~~~
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57:
    note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to
    buffer pointer valid for a defined scope
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^
...
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/Compression.swift:140:14:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:61:34:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WebSocketClient: class {
                                     ^~~~~
                                     AnyObject
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:119:35:
    warning: using 'class' keyword to define a class-constrained protocol is deprecated; use 'AnyObject' instead
    public protocol WSStreamDelegate: class {
                                      ^~~~~
     ...                                
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1326:14:
    warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R)
    rethrows -> R` instead
            data.withUnsafeBytes { _ = CC_SHA1($0, CC_LONG(data.count), &digest) }
                 ^
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Starscream/Sources/Starscream/WebSocket.swift:1327:16:
    warning: 'init(bytes:)' is deprecated: use `init(_:)` instead
            return Data(bytes: digest).base64EncodedString()
                   ^
    ld: in
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Sodium/Sodium/libsodium/libsodium-ios.a(libsodium_la-ae
    ad_xchacha20poly1305.o), building for iOS Simulator, but linking in object file built for iOS, for architecture
    arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    note: Using new build system
    note: Planning
    note: Build preparation complete
    note: Building targets in dependency order
    warning: Capabilities for Signing & Capabilities may not function correctly because its entitlements use a
    placeholder team ID. To resolve this, select a development team in the Runner editor. (in target 'Runner' from
    project 'Runner')
    /Users/zia/Desktop/projects/com_tingsapp_mover/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment
    target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0
    to 15.2.99. (in target 'leveldb-library' from project 'Pods')


Could not build the application for the simulator.
Error launching application on iPhone 13.

I could not find any related message in the above error This is flutter --version

% flutter --version 
Flutter 2.8.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 77d935af4d (7 weeks ago) • 2021-12-16 08:37:33 -0800
Engine • revision 890a5fca2e
Tools • Dart 2.15.1

and this is my info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>Tingsapp Mover</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>com_tingsapp_mover</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>$(FLUTTER_BUILD_NAME)</string>
	<key>CFBundleSignature</key>
	<string>????</string>
	<key>CFBundleVersion</key>
	<string>$(FLUTTER_BUILD_NUMBER)</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIMainStoryboardFile</key>
	<string>Main</string>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<true/>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>This app require to access your location when open</string>
	<key>LSApplicationQueriesSchemes</key>
	<array>
		<string>tel</string>
		<string>https</string>
		<string>http</string>
	</array>
	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSExceptionDomains</key>
		<dict>
			<key>tingsapp.com</key>
			<dict>
				<key>NSExceptionAllowsInsecureHTTPLoads</key>
				<true/>
				<key>NSIncludesSubdomains</key>
				<true/>
			</dict>
		</dict>
	</dict>
</dict>
</plist>

This is how I connect to pusher

import 'package:pusher_client/pusher_client.dart';
...
...

class Messages extends StatefulWidget {
  final Room room;
  final int user;
  const Messages({Key? key, required this.room, required this.user})
      : super(key: key);

  @override
  _MessagesState createState() => _MessagesState();
}

class _MessagesState extends State<Messages> {
  TextEditingController _messageController = TextEditingController();
  PusherClient? pusher;
  Channel? channel;
  List<Message> messages = [];

  @override
  void initState() {
    _initPusher();
    super.initState();
  }

  @override
  void dispose() {
    channel?.unbind('chat-event');
    pusher?.unsubscribe('chat.' + widget.room.id.toString());
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Message")),
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            FutureBuilder(
              future: _get(),
              builder: (context, snapshot) {
                if (snapshot.hasData ||
                    snapshot.connectionState == ConnectionState.done) {
                  return Expanded(
                    child: ListView.builder(
                      reverse: true,
                      padding: EdgeInsets.only(top: 12, left: 12, right: 12),
                      shrinkWrap: true,
                      itemCount: messages.length,
                      itemBuilder: (context, index) {
                        return Column(
                          children: [
                            _buildMyMessage(messages[index]) != null
                                ? MyMessageCard(
                                    message: _buildMyMessage(messages[index]))
                                : Container(),
                            _buildFriendMessage(messages[index]) != null
                                ? FriendMessageCard(
                                    message:
                                        _buildFriendMessage(messages[index]))
                                : Container(),
                          ],
                        );
                      },
                    ),
                  );
                } else if (snapshot.hasError) {
                  return Padding(
                    child: Text("Error: ${snapshot.error}"),
                    padding: EdgeInsets.only(top: 8),
                  );
                } else {
                  return Center(
                      child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: circularProgress(context)));
                }
              },
            ),
            Container(
              padding: EdgeInsets.all(5),
              margin: EdgeInsets.all(5),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                crossAxisAlignment: CrossAxisAlignment.end,
                children: [
                  Expanded(
                    child: SizedBox(
                      height: 55,
                      child: Card(
                        elevation: 2,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(50),
                        ),
                        child: Padding(
                          padding: const EdgeInsets.only(
                              left: 18.0, right: 18.0, top: 3),
                          child: TextFormField(
                            controller: _messageController,
                            decoration: InputDecoration(
                                border: InputBorder.none,
                                isDense: true,
                                hintText: 'Message'),
                          ),
                        ),
                      ),
                    ),
                  ),
                  SizedBox(
                    width: 55,
                    height: 55,
                    child: Card(
                      color: Tingsapp.primary,
                      elevation: 2,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(50),
                      ),
                      child: InkWell(
                          onTap: () => _send(context),
                          child: Icon(
                            Icons.send,
                            color: Colors.white,
                          )),
                    ),
                  )
                ],
              ),
            )
          ],
        ),
      ),
    );
  }

  _send(context) async {
    Api api = new Api();
    try {
      var response = await api.post(
        jsonEncode(
          <String, dynamic>{
            'message': _messageController.text,
          },
        ),
        "chat/room/" + "${widget.room.id}" + "/message",
      );
      if (response.statusCode == 200) {
        _messageController.text = "";
        _get();
      }
    } catch (err) {
      showSnackbar(context, '${err.toString()}');
    }
  }

  Future _get() async {
    Api api = new Api();
    try {
      var response =
          await api.get("chat/room/" + "${widget.room.id}" + "/messages");
      if (response.statusCode == 200) {
        var jsonData = jsonDecode(response.body);
        var messageList =
            (jsonData as List).map((e) => Message.fromJson(e)).toList();
        messages = messageList;
        return messages;
      }
      return [];
    } catch (err) {
      showSnackbar(context, '${err.toString()}');
    }
  }
  Future<void> _initPusher() async {
    Store store = new Store();
    String token = await store.read('token');
    try {
      pusher = PusherClient(
        pusherKey,
        PusherOptions(
          host: broadcastPath,
          encrypted: false,
          auth: PusherAuth(
            broadcastPath + "/broadcasting/auth",
            headers: {
              'Content-Type': 'application/json',
              'Authorization': 'Bearer $token'
            },
          ),
          cluster: 'eu',
        ),
        enableLogging: true,
      );
      channel = pusher?.subscribe("private-chat." + widget.room.id.toString());

      pusher?.onConnectionStateChange((state) {
        print(
            "previousState: ${state?.previousState}, currentState: ${state?.currentState}");
      });

      pusher?.onConnectionError((error) {
        print("error: ${error?.message}");
      });

      channel?.bind('chat-event', (event) {
        setState(() {});
      });
    } catch (e) {
      print(e.toString());
    }
  }
}

But the moment I comment out the above file and pusher_client: ^2.0.0 in pubspec.yaml and then run flutter run my application gets run on ios simulator.
Can anyone help please

More Platforms

I want to use pusher with more platforms like Web and Windows.
Will you update it for support more platforms?

Doesn't seem to work with Laravel Websockets self hosted pusher

I have been commenting on many issues and no one is responding.

I am not able to get this to work. While i was using an older deprecated package called flutter_pusher_client which is very similar in syntax it is working flawlessly.

What seems to be the problem with this package and laravel self hosted pusher option?

Does anyone have a working sample with the same stack as me?

Thanks.

throws exception when listening to events

E/flutter ( 3187): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: PlatformException(ON_EVENT_ERROR, com.google.gson.internal.LinkedTreeMap cannot be cast to java.lang.String, java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.lang.String
E/flutter ( 3187): at com.pusher.client.channel.PusherEvent.getData(PusherEvent.java:40)
E/flutter ( 3187): at com.github.chinloyal.pusher_client.pusher.listeners.FlutterBaseChannelEventListener.onEvent$lambda-0(FlutterBaseChannelEventListener.kt:23)
E/flutter ( 3187): at com.github.chinloyal.pusher_client.pusher.listeners.FlutterBaseChannelEventListener.$r8$lambda$QLL3RY_DOP1OzB8zy2tM2lJPbw0(Unknown Source:0)
E/flutter ( 3187): at com.github.chinloyal.pusher_client.pusher.listeners.FlutterBaseChannelEventListener$$ExternalSyntheticLambda0.run(Unknown Source:4)
E/flutter ( 3187): at android.os.Handler.handleCallback(Handler.java:938)
E/flutter ( 3187): at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter ( 3187): at android.os.Looper.loopOnce(Looper.java:211)
E/flutter ( 3187): at android.os.Looper.loop(Looper.java:300)
E/flutter ( 3187): at android.app.ActivityThread.main(ActivityThread.java:8279)
E/flutter ( 3187): at java.lang.reflect.Method.invoke(Native Method)
E/flutter ( 3187): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:576)
E/flutter ( 3187): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1074)
E/flutter ( 3187): , null)
E/flutter ( 3187):

this is d event the server sends in json
{type: 'api-message', time: '17:43:37', details: 'Channel: channel, Event: App\Events\RealTimeMessage', data: '{"name":"abdul","message":"hello0000000000","time":"2022-10-06T17:43:37+00:00"}'}

pusher Package is not working for ios devices

There are 2 Problems

First:
The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, in Flutter How can I change the minimum IOS Deploying Target.
I have changes and followed stackoverflow solutions but after thats its giving me these errors see in attached file
Screenshot 2021-09-13 at 12 25 06 PM

I cannot get data

How I get data from Pusher to use them?

      PusherOptions options = PusherOptions(
            host: 'example.com,
            wsPort: 6001,
            wssPort: 6001,
            encrypted: true,
            auth: PusherAuth('https://example.com/api/broadcasting/auth',
                headers: {
                  'Authorization': 'Bearer $token',
                  'Content-Type': 'application/json',
                }),
          );
          PusherClient pusher = PusherClient('example', options,
              enableLogging: true, autoConnect: false);
          pusher.connect();

          pusher.onConnectionStateChange((state) {
            print(
                "previousState: ${state!.previousState}, currentState: ${state.currentState}");
          });

          pusher.onConnectionError((error) {
            print("error: ${error!.message}");
          });

          pusher.subscribe("private-Notification.${userId.toString()}").bind(
              "Illuminate\\Notifications\\Events\\BroadcastNotificationCreated",
              (event) {
            print('Notification Data');
            print(event!.data);
          });
        } on Exception catch (e) {
          print('Error' + e.toString());
        }

Result

W/FlutterJNI(32537): Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: com.github.chinloyal/pusher_client_stream. Response ID: 0

D/PusherClientPlugin(32537): [ON_EVENT] Channel: private-Notification.441, EventName: Illuminate\Notifications\Events\BroadcastNotificationCreated,

D/PusherClientPlugin(32537): Data: {"data":"Hello"}, User Id: null

IOS : Unable to parse string as JSON - check that your JSON is valid.

Hi , I'm using : flutter_pusher: ^1.0.2

here is my flutter doctor :

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, 2.2.0-10.2.pre, on macOS 11.2.3 20D91 darwin-x64, locale en-EG)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.1)
[✓] VS Code (version 1.55.2)
[✓] Connected device (2 available)

• No issues found!

when bind to new event on pusher console i got in xcode :

2021-05-09 21:16:44.921819+0200 Runner[51749:732568] Metal API Validation Enabled
2021-05-09 21:16:45.079714+0200 Runner[51749:732999] flutter: Observatory listening on http://127.0.0.1:58979/NtaMnrrTlHQ=/
Pusher init
Pusher connect
2021-05-09 21:19:55.961112+0200 Runner[51749:738889] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Pusher subscribe
Pusher bind (Conversation)
Unable to parse string as JSON - check that your JSON is valid.
Unable to parse string as JSON - check that your JSON is valid.

Building for iOS fails

Steps to reproduce

  1. Install the latest Flutter version
  2. Create a new project
  3. Add pusher_client to the pubspec.yaml
  4. Execute flutter run (I'm building for the iPhone 12 Pro Max simulator)

Expected behavior

I'd expect the app to compile and run in the iOS simulator.

Actual behavior

I get the following error:

Failed to build iOS app
Error output from Xcode build:
↳
    objc[55793]: Class AMSupportURLConnectionDelegate is implemented in both /usr/lib/libauthinstall.dylib (0x1f2527b78) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x113d702c8). One of the two will be used. Which one is undefined.
    objc[55793]: Class AMSupportURLSession is implemented in both /usr/lib/libauthinstall.dylib (0x1f2527bc8) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x113d70318). One of the two will be used. Which one is undefined.
    ** BUILD FAILED **


Xcode's output:
↳
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:59:25: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:29: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:33: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:140:14: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
                 ^
    Command CompileSwift failed with a nonzero exit code
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:59:25: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:29: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:33: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:140:14: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
                 ^
    Command CompileSwift failed with a nonzero exit code
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:59:25: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            return try data.withUnsafeBytes { (bytes:UnsafePointer<UInt8>) -> Data in
                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:29: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:83:57: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                            ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:33: warning: initialization of 'UnsafeMutablePointer<UInt8>' results in a dangling pointer
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: implicit argument conversion from '[UInt8]' to 'UnsafeMutablePointer<UInt8>' produces a pointer valid only for the duration of the call to 'init(_:)'
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^~~~~~~
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:145:61: note: use the 'withUnsafeMutableBufferPointer' method on Array in order to explicitly convert argument to buffer pointer valid for a defined scope
                    strm.next_out = UnsafeMutablePointer<UInt8>(&buffer)
                                                                ^
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Starscream/Sources/Starscream/Compression.swift:140:14: warning: 'withUnsafeBytes' is deprecated: use `withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
            data.withUnsafeBytes { (ptr:UnsafePointer<UInt8>) -> Void in
                 ^
    Command CompileSwift failed with a nonzero exit code
    ld: in /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Sodium/Sodium/libsodium/libsodium-ios.a(libsodium_la-aead_xchacha20poly1305.o), building for iOS Simulator, but linking in object file built for iOS, for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    note: Using new build system
    note: Building targets in parallel
    note: Planning build
    note: Analyzing workspace
    note: Constructing build description
    note: Build preparation complete
    warning: Capabilities for Signing & Capabilities may not function correctly because its entitlements use a placeholder team ID. To resolve this, select a development team in the Runner editor. (in target 'Runner' from project 'Runner')
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.5.99. (in target 'Starscream' from project 'Pods')
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.5.99. (in target 'Sodium' from project 'Pods')
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.5.99. (in target 'ReachabilitySwift' from project 'Pods')
    /Users/thijskuilman/AndroidStudioProjects/flutter_app/ios/Pods/Pods.xcodeproj: warning: The iOS Simulator deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.5.99. (in target 'PusherSwiftWithEncryption' from project 'Pods')

Could not build the application for the simulator.
Error launching application on iPhone 12 Pro Max.

Output of flutter doctor:

[✓] Flutter (Channel stable, 2.5.2, on macOS 11.6 20G165 darwin-arm, locale en-NL)
    • Flutter version 2.5.2 at /Users/thijskuilman/Development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 3595343e20 (3 days ago), 2021-09-30 12:58:18 -0700
    • Engine revision 6ac856380f
    • Dart version 2.14.3

[!] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Users/thijskuilman/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.5.1, Build version 12E507
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] Connected device (3 available)
    • iPhone 12 Pro Max (mobile) • 4EC79A64-B642-574118224945 • ios            
    • com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
    • macOS (desktop)            • macos                                • darwin-arm64   • macOS 11.6 20G165 darwin-arm
    • Chrome (web)               • chrome                               • web-javascript • Google Chrome 

Event Bind not working

Everything is fine working, i even connected to private channels but the problem is your package doesn't listen events event i tried with public events but no luck, i can see in console these logs

Launching lib\main.dart on sdk gphone x86 arm in debug mode...
√ Built build\app\outputs\flutter-apk\app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:56524/Tkxj2peMOho=/ws
D/PusherClientPlugin(26252): Pusher initialized
D/PusherClientPlugin(26252): Event stream cancelled.
D/PusherClientPlugin(26252): Event stream listening...
D/PusherClientPlugin(26252): [BIND] TestEvent
W/System.err(26252): SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
W/System.err(26252): SLF4J: Defaulting to no-operation (NOP) logger implementation
W/System.err(26252): SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
D/PusherClientPlugin(26252): [CONNECTING]
I/flutter (26252): previousState: DISCONNECTED, currentState: CONNECTING
D/PusherClientPlugin(26252): [CONNECTED]
I/flutter (26252): previousState: CONNECTING, currentState: CONNECTED
D/PusherClientPlugin(26252): [PRIVATE] Subscribed: private-helloworld
D/PusherClientPlugin(26252): [ON_EVENT] Channel: private-helloworld, EventName: pusher:subscription_succeeded,
D/PusherClientPlugin(26252): Data: null, User Id: null

cant't change PusherAuth

My application uses JWT Token, and it’s only valid for five minutes.

But now I cannot change the Auth setting of Pusher

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.