Skip to main content

You are looking at Signaling v1.x Docs. The newest version is  Signaling 2.x

Version: 1.x

SDK quickstart

This page shows you how to create your first Signaling app using Signaling SDK.

Understand the tech

Log in to Signaling

The login process includes:

  1. The app client requests a token from your app server.

  2. The app server returns the token to the app client.

  3. The app client logs in to Signaling with the token.

Peer-to-peer messaging

The peer messaging process includes:

  1. Client A sends a peer message to Signaling.

  2. Signaling sends the message to client B. Client B receives the peer message.

Channel messaging

The channel messaging process includes:

  1. Client A creates a channel and join the channel.

  2. Client B and client C joins the channel created by client A.

  3. Client A sends a channel message to Signaling.

  4. Signaling sends the channel message to client B and C. Client B and client C receives the message.

For an app client to join a channel, you need the following information:

  • The App ID: A randomly generated string provided by Agora for identifying your app. You can get the App ID from Agora Console.

  • The user ID: The unique identifier of a user. You need to specify the user ID yourself, and ensure that it is unique in the channel.

  • A token: In a test or production environment, your app client retrieves tokens from your server.

  • The channel name: A string that identifies the channel for the channel messaging.

Prerequisites

In order to follow this procedure you must have:

  • Xcode 12.0 or higher.
  • A device running macOs 10.11 or higher.
  • An Apple developer account
  • An Agora account and project.

  • A computer with Internet access.

    Ensure that no firewall is blocking your network communication.

Next steps

Generating a token by hand is not helpful in a production context. Authenticate Your Users with Tokens shows you how to start live streaming with a token that you retrieve from your server.

Project setup

In this section, we create a Unity project and integrate the SDK into the project.

1. Create a macOS project in Xcode

The following steps show how to create a macOS App in Xcode:

  • Enter RtmQuickstart as the Product Name.

  • Enter agora as the Organization Identifier.

  • Select User Interface as Storyboard.

  • Select Language as Objective-C.

2. Integrate the SDK

  1. In Terminal, go to the project path and run the pod init command to create a Podfile in the project folder.

  2. Open the Podfile, delete all contents and input the following contents.

    # platform :macos, '10.10'
    target 'RtmQuickstart' do
    use_frameworks!
    pod 'AgoraRtm_macOS'
    end
    Copy
  3. Run the pod update command to update the local libraries.

  4. Run the pod install command to install the Agora SDK. Once you successfully install the SDK, it shows Pod installation complete! in Terminal, and you can see a workspace file in the project folder.

If you are in China, and have network problems that lead to the failed execution of the pod command, you can use mirror sites such as Gitee Mirror or TUNA Mirror.

Implement Signaling

1. Create the UI

  1. Open the Main.storyboard file in Xcode, edit it in Text mode, and replace the contents of the file with the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="XfG-lQ-9wD">
    <dependencies>
    <deployment identifier="macosx"/>
    <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="16097.2"/>
    <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
    <!--Application-->
    <scene sceneID="JPo-4y-FX3">
    <objects>
    <application id="hnw-xV-0zn" sceneMemberID="viewController">
    <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
    <items>
    <menuItem title="RtmQuickstart" id="1Xt-HY-uBw">
    <modifierMask key="keyEquivalentModifierMask"/>
    <menu key="submenu" title="RtmQuickstart" systemMenu="apple" id="uQy-DD-JDr">
    <items>
    <menuItem title="About RtmQuickstart" id="5kV-Vb-QxS">
    <modifierMask key="keyEquivalentModifierMask"/>
    <connections>
    <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
    </connections>
    </menuItem>
    <menuItem title="Quit RtmQuickstart" keyEquivalent="q" id="4sb-4s-VLi">
    <connections>
    <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
    </connections>
    </menuItem>
    </items>
    </menu>
    </menuItem>
    </items>
    </menu>
    <connections>
    <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
    </connections>
    </application>
    <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
    <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
    <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
    </objects>
    <point key="canvasLocation" x="75" y="0.0"/>
    </scene>
    <!--Window Controller-->
    <scene sceneID="R2V-B0-nI4">
    <objects>
    <windowController id="B8D-0N-5wS" sceneMemberID="viewController">
    <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
    <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
    <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
    <rect key="contentRect" x="196" y="240" width="633" height="270"/>
    <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
    <connections>
    <binding destination="B8D-0N-5wS" name="representedFilename" keyPath="self.MsgTextView" id="IH6-q2-gSp"/>
    <outlet property="delegate" destination="B8D-0N-5wS" id="98r-iN-zZc"/>
    </connections>
    </window>
    <connections>
    <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
    </connections>
    </windowController>
    <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
    </objects>
    <point key="canvasLocation" x="151.5" y="250"/>
    </scene>
    <!--View Controller-->
    <scene sceneID="hIz-AP-VOD">
    <objects>
    <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController">
    <view key="view" id="m2S-Jp-Qdl">
    <rect key="frame" x="0.0" y="0.0" width="672" height="466"/>
    <autoresizingMask key="autoresizingMask"/>
    <subviews>
    <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vhs-Qx-cHl">
    <rect key="frame" x="117" y="393" width="172" height="27"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="4qa-bq-d5v">
    <font key="font" usesAppearanceFont="YES"/>
    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6pf-RU-bA5">
    <rect key="frame" x="36" y="399" width="49" height="16"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" lineBreakMode="clipping" title="User ID" id="l8T-HD-eJJ">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7dp-23-vRo">
    <rect key="frame" x="36" y="348" width="67" height="16"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" lineBreakMode="clipping" title="ChannelID" id="LCQ-eF-Nf6">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7zu-6p-vJj">
    <rect key="frame" x="117" y="342" width="172" height="27"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="4NN-2G-iTL">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eZF-Je-F07">
    <rect key="frame" x="117" y="284" width="360" height="27"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="x8V-FH-HnS">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ubg-em-Lwh">
    <rect key="frame" x="10" y="293" width="100" height="16"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" lineBreakMode="clipping" title="Group Message" id="iKx-sY-uuc">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hnI-nz-lHy">
    <rect key="frame" x="12" y="247" width="90" height="16"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" lineBreakMode="clipping" title="Peer Message" id="HNY-nO-pn1">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="l5d-LC-xJP">
    <rect key="frame" x="117" y="237" width="360" height="28"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="Itb-hN-7on">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8ld-U7-qEb">
    <rect key="frame" x="381" y="389" width="74" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Login" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ZIB-oj-s8Y">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="Login:" target="XfG-lQ-9wD" id="Pfy-Nu-Lmf"/>
    </connections>
    </button>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="h2Z-Uu-Bpv">
    <rect key="frame" x="581" y="389" width="83" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Logout" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="BSD-Se-apF">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="Logout:" target="XfG-lQ-9wD" id="eHM-Jj-e7z"/>
    </connections>
    </button>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q1A-Uy-iY2">
    <rect key="frame" x="381" y="335" width="66" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Join" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="KpO-us-tGE">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="JoinChannel:" target="XfG-lQ-9wD" id="Yvm-jb-ow0"/>
    </connections>
    </button>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="uaV-MT-mPj">
    <rect key="frame" x="584" y="335" width="76" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Leave" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="dZn-qK-4cK">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="LeaveChannel:" target="XfG-lQ-9wD" id="MWd-IT-Uip"/>
    </connections>
    </button>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zfe-Ec-M4n">
    <rect key="frame" x="587" y="281" width="71" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Send" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="rbh-Vm-cYi">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="SendGroupMsg:" target="XfG-lQ-9wD" id="pDh-8Z-2mK"/>
    </connections>
    </button>
    <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c09-B2-Vz3">
    <rect key="frame" x="587" y="230" width="71" height="32"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <buttonCell key="cell" type="push" title="Send" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="MbO-Qp-1fw">
    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
    <font key="font" metaFont="system"/>
    </buttonCell>
    <connections>
    <action selector="SendPeerMsg:" target="XfG-lQ-9wD" id="6DP-jS-kAU"/>
    </connections>
    </button>
    <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ykl-lc-LSx">
    <rect key="frame" x="489" y="237" width="96" height="28"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="vqf-ce-X3Z">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="EVS-Pk-gmz">
    <rect key="frame" x="513" y="273" width="48" height="16"/>
    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
    <textFieldCell key="cell" lineBreakMode="clipping" title="Peer ID" id="F09-kd-FIl">
    <font key="font" metaFont="system"/>
    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    </textFieldCell>
    </textField>
    <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Q8T-ql-eg2">
    <rect key="frame" x="12" y="20" width="640" height="209"/>
    <autoresizingMask key="autoresizingMask"/>
    <clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="SYc-Iw-hu7">
    <rect key="frame" x="0.0" y="0.0" width="625" height="209"/>
    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
    <subviews>
    <textView importsGraphics="NO" richText="NO" verticallyResizable="YES" spellingCorrection="YES" smartInsertDelete="YES" id="c5T-WT-B0b">
    <rect key="frame" x="0.0" y="0.0" width="625" height="209"/>
    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
    <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
    <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
    <size key="minSize" width="625" height="209"/>
    <size key="maxSize" width="766" height="10000000"/>
    <color key="insertionPointColor" name="textColor" catalog="System" colorSpace="catalog"/>
    </textView>
    </subviews>
    </clipView>
    <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="XoY-7p-i18">
    <rect key="frame" x="-100" y="-100" width="225" height="15"/>
    <autoresizingMask key="autoresizingMask"/>
    </scroller>
    <scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="uNS-n6-n8J">
    <rect key="frame" x="625" y="0.0" width="15" height="209"/>
    <autoresizingMask key="autoresizingMask"/>
    </scroller>
    </scrollView>
    </subviews>
    </view>
    <connections>
    <outlet property="ChannelIDTextField" destination="7zu-6p-vJj" id="VWt-Bh-24b"/>
    <outlet property="GroupMsgButton" destination="zfe-Ec-M4n" id="izK-67-iY2"/>
    <outlet property="GroupMsgTextField" destination="eZF-Je-F07" id="vK6-i3-788"/>
    <outlet property="JoinButton" destination="Q1A-Uy-iY2" id="WxT-j2-kUE"/>
    <outlet property="LeaveButton" destination="uaV-MT-mPj" id="QpT-38-W6F"/>
    <outlet property="LoginButton" destination="8ld-U7-qEb" id="gtb-XO-CRg"/>
    <outlet property="LogoutButton" destination="h2Z-Uu-Bpv" id="OfC-dx-4fM"/>
    <outlet property="MsgTextView" destination="Q8T-ql-eg2" id="jnO-2R-T1w"/>
    <outlet property="PeerMsgButton" destination="c09-B2-Vz3" id="8aS-cj-N0n"/>
    <outlet property="PeerMsgTextField" destination="l5d-LC-xJP" id="XFD-ar-Sm5"/>
    <outlet property="UserIDTextField" destination="Vhs-Qx-cHl" id="4ty-Po-1oM"/>
    </connections>
    </viewController>
    <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
    </objects>
    <point key="canvasLocation" x="158" y="753"/>
    </scene>
    </scenes>
    </document>
    Copy
  2. Make sure you set the View Controller Scene as Storyboard Entry Point.

    1623406434804

2. Implement the logic of sending and receiving messages

To help you quickly understand and implement functions of Agora Signaling, this section shows how to implement the following functions in a single view with minimum effort:

  • Log in to and log out of Agora Signaling

  • Join and leave a channel

  • Send and receive peer-to-peer or channel messages

  • See the changes in connection state of the user

To implement this functionality:

  1. In Xcode, replace the contents of the ViewController.h file with the following:

    //
    // ViewController.h
    // RtmQuickstart
    //
    // Created by macoscatalina on 2021/6/10.
    // Copyright © 2021 macoscatalina. All rights reserved.
    //

    #import <Cocoa/Cocoa.h>

    #import <AgoraRtmKit/AgoraRtmKit.h>

    @interface ViewController : NSViewController

    // Buttons
    @property (weak, nonatomic) IBOutlet NSButton *LoginButton;
    @property (weak, nonatomic) IBOutlet NSButton *LogoutButton;
    @property (weak, nonatomic) IBOutlet NSButton *JoinButton;
    @property (weak, nonatomic) IBOutlet NSButton *LeaveButton;
    @property (weak, nonatomic) IBOutlet NSButton *GroupMsgButton;
    @property (weak, nonatomic) IBOutlet NSButton *PeerMsgButton;

    // Textfields
    @property (weak, nonatomic) IBOutlet NSTextField *UserIDTextField;
    @property (weak, nonatomic) IBOutlet NSTextField *ChannelIDTextField;
    @property (weak, nonatomic) IBOutlet NSTextField *GroupMsgTextField;
    @property (weak, nonatomic) IBOutlet NSTextField *PeerMsgTextField;
    @property (weak, nonatomic) IBOutlet NSTextField *PeerIDTextField;

    @property (weak) IBOutlet NSScrollView *MsgTextView;

    @end
    Copy
  2. In Xcode, replace the contents of the ViewController.m file with the following: You need to replace Your_App_ID with the App ID of your project, and Your_Token with the Token you obtained.

    //
    // ViewController.m
    // RtmQuickstart
    //
    // Created by macoscatalina on 2021/6/10.
    // Copyright © 2021 macoscatalina. All rights reserved.
    //

    #import "ViewController.h"

    @interface ViewController ()<AgoraRtmChannelDelegate, AgoraRtmDelegate>

    @property(nonatomic, strong)AgoraRtmKit* kit;
    @property(nonatomic, strong)AgoraRtmChannel* channel;
    @property(nonatomic, strong)AgoraRtmSendMessageOptions* options;

    @property NSString* appID;
    @property NSString* token;

    @property NSString* uid;
    @property NSString* peerID;
    @property NSString* channelID;
    @property NSString* peerMsg;
    @property NSString* channelMsg;

    @property NSString* text;
    @property NSMutableArray* textArray;
    @property NSTextView* textView;

    * (void)AddMsgToRecord:(NSString*)text;

    @end

    @implementation ViewController

    * (void)viewDidLoad {
    [super viewDidLoad];
    // Enter your App ID
    self.appID = @"Your_App_ID";
    // Create an AgoraRtmKit instance
    _kit = [[AgoraRtmKit alloc] initWithAppId:self.appID delegate:self];
    self.textArray = [[NSMutableArray alloc]init];
    }

    // Add message to the UI TextView
    - (void)AddMsgToRecord:(NSString*)text {


    [self.textArray addObject:(self.text)];
    NSSize contentSize = [self.MsgTextView contentSize];
    self.textView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, contentSize.height, contentSize.width)];
    [self.textView setTextColor:NSColor.blueColor];
    [self.textView setString:[self.textArray componentsJoinedByString:(@"\n")]];
    [self.MsgTextView setDocumentView:self.textView];


    }

    // Button to log in to Signaling
    - (IBAction)Login:(id)sender {
    self.uid = [self.UserIDTextField stringValue];
    // Enter your token
    self.token = @"Your_Token";
    // Log in to Signaling
    [_kit loginByToken:(self.token) user:(self.uid) completion:^(AgoraRtmLoginErrorCode errorCode) {
    if (errorCode != AgoraRtmLoginErrorOk){
    self.text = [NSString stringWithFormat:@"Login failed for user %@. Code: %ld",self.uid, (long)errorCode];
    NSLog(@"%@", self.text);
    }
    else {
    self.text = [NSString stringWithFormat:@"Login successful for user %@. Code: %ld",self.uid, (long)errorCode];
    NSLog(@"%@", self.text);
    }

    [self AddMsgToRecord:(self.text)];

    }

    ];}


    // Button to log out of Signaling
    - (IBAction)Logout:(id)sender {
    // Log out of Signaling
    [_kit logoutWithCompletion:^(AgoraRtmLogoutErrorCode errorCode) {
    if (errorCode == AgoraRtmLogoutErrorOk){
    self.text = [NSString stringWithFormat:@"Logout successful. Code: %ld",(long)errorCode];
    NSLog(@"%@", self.text);
    } else {


    self.text = [NSString stringWithFormat:@"Logout failed. Code: %ld",(long)errorCode];
    NSLog(@"%@", self.text); }

    [self AddMsgToRecord:(self.text)];

    }];


    }

    // Button to join the <Vg k="MESS" /> channel
    - (IBAction)JoinChannel:(id)sender {

    self.channelID = [self.ChannelIDTextField stringValue];
    // Create an <Vg k="MESS" /> channel
    _channel = [_kit createChannelWithId:self.channelID delegate:self];
    // Join an <Vg k="MESS" /> channel
    [_channel joinWithCompletion:^(AgoraRtmJoinChannelErrorCode errorCode) {

    if(errorCode == AgoraRtmJoinChannelErrorOk){
    self.text = [NSString stringWithFormat:@"Successfully joined channel %@ Code: %ld",self.channelID,(long)errorCode];
    NSLog(@"%@", self.text);
    } else {

    self.text = [NSString stringWithFormat:@"Failed to join channel %@ Code: %ld",self.channelID, (long)errorCode];
    NSLog(@"%@", self.text); }

    [self AddMsgToRecord:(self.text)];
    }];

    }

    -(void)channel:(AgoraRtmChannel *)channel memberLeft:(AgoraRtmMember *)member
    {
    self.text = [NSString stringWithFormat:@"%@ left channel %@", member.channelId, member.userId];
    [self AddMsgToRecord:(self.text)];
    }

    -(void)channel:(AgoraRtmChannel *)channel memberJoined:(AgoraRtmMember *)member
    {
    self.text = [NSString stringWithFormat:@"%@ joined channel %@", member.channelId, member.userId];
    [self AddMsgToRecord:(self.text)];
    }

    // Button to leave the <Vg k="MESS" /> channel
    - (IBAction)LeaveChannel:(id)sender {
    [_channel leaveWithCompletion:^(AgoraRtmLeaveChannelErrorCode errorCode) {
    if (errorCode == AgoraRtmLeaveChannelErrorOk){
    self.text = [NSString stringWithFormat:@"Leave channel successful Code: %ld", (long)errorCode];
    } else {
    self.text = [NSString stringWithFormat:@"Failed to leave channel Code: %ld", (long)errorCode]; }


    [self AddMsgToRecord:(self.text)];
    }];


    }

    // Button to send group message
    - (IBAction)SendGroupMsg:(id)sender {


    self.channelMsg = [self.GroupMsgTextField stringValue];

    self.options.enableOfflineMessaging = true;

    [_channel sendMessage:[[AgoraRtmMessage alloc] initWithText:self.channelMsg] sendMessageOptions:self.options completion:^(AgoraRtmSendChannelMessageErrorCode errorCode) {
    if (errorCode == AgoraRtmSendChannelMessageErrorOk)
    {
    self.text = [NSString stringWithFormat:@"Message sent to channel %@ : %@", self.channelID, self.channelMsg]; }
    else
    {
    self.text = [NSString stringWithFormat:@"Message failed to send to channel %@ : %@ ErrorCode: %ld", self.channelID, self.channelMsg, (long)errorCode];
    }

    [self AddMsgToRecord:(self.text)];
    }];

    }

    // Display received group message
    - (void)channel:(AgoraRtmChannel *)channel messageReceived:(AgoraRtmMessage *)message fromMember:(AgoraRtmMember *)member
    {
    self.text = [NSString stringWithFormat:@"Message received in channel: %@ from user: %@ content: %@",member.channelId, member.userId, message.text];
    [self AddMsgToRecord:(self.text)];
    }

    // Button to send peer message
    - (IBAction)SendPeerMsg:(id)sender {

    self.peerMsg = [self.PeerMsgTextField stringValue];
    self.peerID = [self.PeerIDTextField stringValue];

    [_kit sendMessage:[[AgoraRtmMessage alloc] initWithText:self.peerMsg] toPeer:self.peerID completion:^(AgoraRtmSendPeerMessageErrorCode errorCode) {
    if (errorCode == AgoraRtmSendPeerMessageErrorOk)
    {
    self.text = [NSString stringWithFormat:@"Message sent from user: %@ to user: %@ content: %@", self.uid, self.peerID, self.peerMsg];
    }
    else
    {
    self.text = [NSString stringWithFormat:@"Message failed to send from user: %@ to user: %@ content: %@ Error: %ld", self.uid, self.peerID, self.peerMsg, (long)errorCode]; }
    [self AddMsgToRecord:(self.text)];

    }];

    }

    // Display received peer message
    - (void)rtmKit:(AgoraRtmKit *)kit messageReceived:(AgoraRtmMessage _)message fromPeer:(NSString_)peerId
    {
    self.text = [NSString stringWithFormat:@"Message received from user: %@ content: %@", peerId, message.text];
    [self AddMsgToRecord:(self.text)];}

    // Display connection status of the current user
    - (void)rtmKit:(AgoraRtmKit *)kit connectionStateChanged:(AgoraRtmConnectionState)state reason:(AgoraRtmConnectionChangeReason)reason
    {
    self.text = [NSString stringWithFormat:@"Connection status changed to: %ld Reason: %ld", (long)state, (long)reason];
    [self AddMsgToRecord:(self.text)];
    }

    * (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
    }

    @end
    Copy

Test your app

Compile and run the project on a simulator or a physical mobile device. You can see the following page if your project runs successfully:

1623407401770

Considerations

  • The Agora Signaling SDK supports creating multiple AgoraRtmKit/) instances that are independent of each other.

  • To send and receive peer-to-peer or channel messages, ensure that you have successfully logged in the Agora Signaling (you have received AgoraRtmLoginErrorOk).

  • To use any of the channel features, you must first call the createChannelWithId method to create a channel instance.

  • You can create multiple channel instances for each AgoraRtmKit) instance, but you can only join a maximum of 20 channels at the same time. The channelId parameter needs to be channel-specific.

  • When you leave a channel and do not want to join it again, you can call the destroyChannelWithId method to release all resources used by the channel instance.

  • You cannot reuse a received AgoraRtmMessage instance.

Next steps

Generating a token by hand is not helpful in a production context. Authenticate Your Users with Tokens shows you how to start Signaling with a token that you retrieve from your server.

See also

Sample project

Agora also provides an open-source [sample project](https://github.com/AgoraIO/Signaling/tree/master/Agora-Signaling-Tutorial-macOS-Objective-C) for Objective-C and [sample project](https://github.com/AgoraIO/Signaling/tree/master/Agora-Signaling-Tutorial-macOS) for Swift on GitHub for your reference.

SDK Integration Methods

Downloads shows you alternative ways to add Signaling SDK in your project.

Signaling