{"id":20770570,"url":"https://github.com/ably/ably-java","last_synced_at":"2025-04-04T07:06:24.465Z","repository":{"id":23993739,"uuid":"27377253","full_name":"ably/ably-java","owner":"ably","description":"Java, Android, Clojure and Scala client library SDK for Ably realtime messaging service","archived":false,"fork":false,"pushed_at":"2025-03-21T10:30:24.000Z","size":9709,"stargazers_count":85,"open_issues_count":132,"forks_count":40,"subscribers_count":31,"default_branch":"main","last_synced_at":"2025-03-28T06:07:10.356Z","etag":null,"topics":["android","client-library","clojure","java","realtime","realtime-messaging","rest","scala","sdk"],"latest_commit_sha":null,"homepage":"https://ably.com/download","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ably.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-01T11:54:06.000Z","updated_at":"2025-03-18T11:08:51.000Z","dependencies_parsed_at":"2023-12-20T09:25:41.103Z","dependency_job_id":"17ed0ca0-c82b-4417-98ff-e53f6388fd82","html_url":"https://github.com/ably/ably-java","commit_stats":null,"previous_names":[],"tags_count":94,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ably","download_url":"https://codeload.github.com/ably/ably-java/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135143,"owners_count":20889420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","client-library","clojure","java","realtime","realtime-messaging","rest","scala","sdk"],"created_at":"2024-11-17T12:10:27.686Z","updated_at":"2025-04-04T07:06:24.459Z","avatar_url":"https://github.com/ably.png","language":"Java","readme":"# [Ably](https://www.ably.io)\n\n[![.github/workflows/check.yml](https://github.com/ably/ably-java/actions/workflows/check.yml/badge.svg)](https://github.com/ably/ably-java/actions/workflows/check.yml)\n[![.github/workflows/integration-test.yml](https://github.com/ably/ably-java/actions/workflows/integration-test.yml/badge.svg)](https://github.com/ably/ably-java/actions/workflows/integration-test.yml)\n[![.github/workflows/emulate.yml](https://github.com/ably/ably-java/actions/workflows/emulate.yml/badge.svg)](https://github.com/ably/ably-java/actions/workflows/emulate.yml)\n[![.github/workflows/javadoc.yml](https://github.com/ably/ably-java/actions/workflows/javadoc.yml/badge.svg)](https://github.com/ably/ably-java/actions/workflows/javadoc.yml)\n[![Features](https://github.com/ably/ably-java/actions/workflows/features.yml/badge.svg)](https://github.com/ably/ably-java/actions/workflows/features.yml)\n\n_[Ably](https://ably.com) is the platform that powers synchronized digital experiences in realtime. Whether attending an event in a virtual venue, receiving realtime financial information, or monitoring live car performance data – consumers simply expect realtime digital experiences as standard. Ably provides a suite of APIs to build, extend, and deliver powerful digital experiences in realtime for more than 250 million devices across 80 countries each month. Organizations like Bloomberg, HubSpot, Verizon, and Hopin depend on Ably’s platform to offload the growing complexity of business-critical realtime data synchronization at global scale. For more information, see the [Ably documentation](https://ably.com/documentation)._\n\n## Overview\n\nA Java Realtime and REST client library.\nThis library currently targets the [Ably client library features spec](https://www.ably.com/docs/client-lib-development-guide/features/) Version 1.2.\n\n## Installation\n\nInclude the library by adding an `implementation` reference to `dependencies` block in your [Gradle](https://gradle.org/) build script.\n\nFor [Java](https://mvnrepository.com/artifact/io.ably/ably-java/latest):\n\n```groovy\nimplementation 'io.ably:ably-java:1.2.52'\n```\n\nFor [Android](https://mvnrepository.com/artifact/io.ably/ably-android/latest):\n\n```groovy\nimplementation 'io.ably:ably-android:1.2.52'\n```\n\nThe library is hosted on [Maven Central](https://mvnrepository.com/repos/central), so you need to ensure that the repository is referenced also; IDEs will typically include this by default:\n\n```groovy\nrepositories {\n\tmavenCentral()\n}\n```\n\nWe only support installation via Maven / Gradle from the Maven Central repository. If you want to use a standalone fat JAR (i.e. containing all dependencies), it can be generated via a Gradle task (see [building](#building) below), creating a \"Java\" (JRE) library variant only. There is no standalone / self-contained AAR build option. Checkout [requirements](#requirements).\n\n## Runtime Requirements\n\nThe library requires that the runtime environment is able to establish a safe TLS connection (TLS v1.2 or v1.3). It will fail to connect with a `SecurityException` if this level of security is not available.\n\n## Usage\n\nPlease refer to the [documentation](https://www.ably.com/docs) for a full API reference.\n\n### Using the Realtime API\n\nThe examples below assume a client has been created as follows:\n\n```java\nAblyRealtime ably = new AblyRealtime(\"xxxxx\");\n```\n\n#### Connection\n\nAblyRealtime will attempt to connect automatically once new instance is created. Also, it offers API for listening connection state changes.\n\n```java\nably.connection.on(new ConnectionStateListener() {\n\t@Override\n\tpublic void onConnectionStateChanged(ConnectionStateChange state) {\n\t\tSystem.out.println(\"New state is \" + state.current.name());\n\t\tswitch (state.current) {\n\t\t\tcase connected: {\n\t\t\t\t// Successful connection\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase failed: {\n\t\t\t\t// Failed connection\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n});\n```\n\n#### Subscribing to a channel\n\nGiven:\n\n```java\nChannel channel = ably.channels.get(\"test\");\n```\n\nSubscribe to all events:\n\n```java\nchannel.subscribe(new MessageListener() {\n\t@Override\n\tpublic void onMessage(Message message) {\n\t\tSystem.out.println(\"Received `\" + message.name + \"` message with data: \" + message.data);\n\t}\n});\n```\n\nor subscribe to certain events:\n\n```java\nString[] events = new String[] {\"event1\", \"event2\"};\nchannel.subscribe(events, new MessageListener() {\n\t@Override\n\tpublic void onMessage(Message message) {\n\t\tSystem.out.println(\"Received `\" + message.name + \"` message with data: \" + message.data);\n\t}\n});\n```\n\n#### Subscribing to a channel in delta mode\n\nSubscribing to a channel in delta mode enables [delta compression](https://www.ably.com/docs/realtime/channels/channel-parameters/deltas). This is a way for a client to subscribe to a channel so that message payloads sent contain only the difference (ie the delta) between the present message and the previous message on the channel.\n\nRequest a Vcdiff formatted delta stream using channel options when you get the channel:\n\n```java\nMap\u003cString, String\u003e params = new HashMap\u003c\u003e();\nparams.put(\"delta\", \"vcdiff\");\nChannelOptions options = new ChannelOptions();\noptions.params = params;\nChannel channel = ably.channels.get(\"test\", options);\n```\n\nBeyond specifying channel options, the rest is transparent and requires no further changes to your application. The `message.data` instances that are delivered to your `MessageListener` continue to contain the values that were originally published.\n\nIf you would like to inspect the `Message` instances in order to identify whether the `data` they present was rendered from a delta message from Ably then you can see if `extras.getDelta().getFormat()` equals `\"vcdiff\"`.\n\n#### Publishing to a channel\n\nData published to a channel (apart from strings or bytearrays) has to be instances of JsonElement to be encoded properly.\n\n```java\n// Publishing message of type String\nchannel.publish(\"greeting\", \"Hello World!\", new CompletionListener() {\n\t@Override\n\tpublic void onSuccess() {\n\t\tSystem.out.println(\"Message successfully sent\");\n\t}\n\n\t@Override\n\tpublic void onError(ErrorInfo reason) {\n\t\tSystem.err.println(\"Unable to publish message; err = \" + reason.message);\n\t}\n});\n\n// Publishing message of type JsonElement\nJsonObject jsonElement = new JsonObject();\n\nMap\u003cString, String\u003e inputMap = new HashMap\u003cString, String\u003e();\ninputMap.put(\"name\", \"Joe\");\ninputMap.put(\"surename\", \"Doe\");\n\nfor (Map.Entry\u003cString, String\u003e entry : inputMap.entrySet()) {\n    jsonElement.addProperty(entry.getKey(), entry.getValue());\n}\n\nchannel.publish(\"greeting\", message, new CompletionListener() {\n\t@Override\n\tpublic void onSuccess() {\n\t\tSystem.out.println(\"Message successfully sent\");\n\t}\n\n\t@Override\n\tpublic void onError(ErrorInfo reason) {\n\t\tSystem.err.println(\"Unable to publish message; err = \" + reason.message);\n\t}\n});\n```\n\n#### Querying the history\n\n```java\nPaginatedResult\u003cMessage\u003e result = channel.history(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Presence on a channel\n\n```java\nchannel.presence.enter(\"john.doe\", new CompletionListener() {\n\t@Override\n\tpublic void onSuccess() {\n\t\t// Successfully entered to the channel\n\t}\n\n\t@Override\n\tpublic void onError(ErrorInfo reason) {\n\t\t// Failed to enter channel\n\t}\n});\n```\n\n#### Querying the presence history\n\n```java\nPaginatedResult\u003cPresenceMessage\u003e result = channel.presence.history(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Channel state\n\n`Channel` extends `EventEmitter` that emits channel state changes, and listening those events is possible with `ChannelStateListener`\n\n```java\nChannelStateListener listener = new ChannelStateListener() {\n\t@Override\n  public void onChannelStateChanged(ChannelStateChange stateChange) {\n    System.out.println(\"Channel state changed to \" + stateChange.current.name());\n    if (stateChange.reason != null)\n        System.out.println(\"Channel state error\" + stateChange.reason.message);\n  }\n};\n```\n\nYou can register using\n\n```java\nchannel.on(listener);\n```\n\nand after you are done listening channel state events, you can unregister using\n```java\nchannel.off(listener);\n```\n\nIf you are interested with specific events, it is possible with providing extra `ChannelState` value.\n\n```java\nchannel.on(ChannelState.attached, listener);\n```\n\n#### Use of authCallback\n\nCallback that provides either tokens (`TokenDetails`), or signed token requests (`TokenRequest`), in response to a request with given token params.\n\n```java\nClientOptions options = new ClientOptions();\n    \noptions.authCallback = new Auth.TokenCallback() {\n    @Override\n    public Object getTokenRequest(Auth.TokenParams params) {\n        System.out.println(\"Token Params: \" + params);\n        // TODO: process params\n        return null; // TODO: return TokenDetails or TokenRequest or JWT string\n    }\n};\n\nAblyRealtime ablyRealtime = new AblyRealtime(options);\n```\n\n### Using the REST API\n\nThe examples below assume a client and/or channel has been created as follows:\n\n```java\nAblyRest ably = new AblyRest(\"xxxxx\");\nChannel channel = ably.channels.get(\"test\");\n```\n\n#### Publishing a message to a channel\n\nGiven the message below\n\n```java\nMessage message = new Message(\"myEvent\", \"Hello\");\n```\n\nSharing synchronously,\n\n```java\nchannel.publish(message);\n```\n\nSharing asynchronously,\n\n```java\nchannel.publishAsync(message, new CompletionListener() {\n  @Override\n\tpublic void onSuccess() {\n\t   System.out.println(\"Message successfully received by Ably server.\");\n\t}\n\n\t@Override\n\tpublic void onError(ErrorInfo reason) {\n\t\tSystem.err.println(\"Unable to publish message to Ably server; err = \" + reason.message);\n\t}\n});\n```\n\n#### Querying the history\n\n```java\nPaginatedResult\u003cMessage\u003e result = channel.history(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Presence on a channel\n\n```java\nPaginatedResult\u003cPresenceMessage\u003e result = channel.presence.get(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Querying the presence history\n\n```java\nPaginatedResult\u003cPresenceMessage\u003e result = channel.presence.history(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Generate a Token and Token Request\n\n```java\nTokenDetails tokenDetails = ably.auth.requestToken(null, null);\nSystem.out.println(\"Success; token = \" + tokenRequest);\n```\n\n#### Fetching your application's stats\n\n```java\nPaginatedResult\u003cStats\u003e stats = ably.stats(null);\n\nSystem.out.println(result.items().length + \" messages received in first page\");\nwhile(result.hasNext()) {\n\tresult = result.getNext();\n\tSystem.out.println(result.items().length + \" messages received in next page\");\n}\n```\n\n#### Fetching the Ably service time\n\n```java\nlong serviceTime = ably.time();\n```\n\n#### Logging\n\nYou can get log output from the library by modifying the log level:\n\n```java\nimport io.ably.lib.util.Log;\n\nClientOptions opts = new ClientOptions(key);\nopts.logLevel = Log.VERBOSE;\nAblyRest ably = new AblyRest(opts);\n...\n```\n\nBy default, log output will go to `System.out` for the java library, and logcat for Android.\n\nYou can redirect the log output to a logger of your own by specifying a custom log handler:\n\n```java\nimport io.ably.lib.util.Log.LogHandler;\n\nClientOptions opts = new ClientOptions(key);\nopts.logHandler = new LogHandler() {\n\tpublic void println(int severity, String tag, String msg, Throwable tr) {\n\t\t/* handle log output here ... */\n\t}\n};\nAblyRest ably = new AblyRest(opts);\n...\n```\n\nNote that any logger you specify in this way has global scope - it will set as a static of the library\nand will apply to all Ably library instances. If you need to release your custom logger so that it can be\ngarbage-collected, you need to clear that static reference:\n\n```java\nimport io.ably.lib.util.Log;\n\nLog.setHandler(null);\n```\n\n#### Threads\n\nAblyRealtime will invoke all callbacks on background thread. \nIf you are using Ably in Android application you must switch to main thread to update UI. \n\n```java\nchannel.presence.enter(\"john.doe\", new CompletionListener() {\n    @Override\n    public void onSuccess() {\n        //If you are in Activity\n        runOnUiThread(new Runnable() {\n        @Override\n        public void run() {\n                //Update your UI here\n            }\n        });\n        \n        //If you are in Fragment or other class\n        Handler handler = new Handler(Looper.getMainLooper());\n        handler.post(new Runnable() {\n            @Override\n            public void run() {\n                //Update your UI here\n            }\n        });\n    }\n});\n```\n\n### Using the Push API\n\n#### Delivering push notifications\n\nSee [documentation](https://www.ably.com/docs/general/push/publish)  for detail.\n\nAbly provides two models for delivering push notifications to devices.\n\nTo publish a message to a channel including a push payload:\n\n```java\nMessage message = new Message(\"example\", \"realtime data\");\nmessage.extras = io.ably.lib.util.JsonUtils.object()\n    .add(\"push\", io.ably.lib.util.JsonUtils.object()\n        .add(\"notification\", io.ably.lib.util.JsonUtils.object()\n            .add(\"title\", \"Hello from Ably!\")\n            .add(\"body\", \"Example push notification from Ably.\"))\n        .add(\"data\", io.ably.lib.util.JsonUtils.object()\n            .add(\"foo\", \"bar\")\n            .add(\"baz\", \"qux\")));\n\nrest.channels.get(\"pushenabled:foo\").publishAsync(message, new CompletionListener() {\n    @Override\n    public void onSuccess() {}\n\n    @Override\n    public void onError(ErrorInfo errorInfo) {\n        // Handle error.\n    }\n});\n```\n\nTo publish a push payload directly to a registered device:\n\n```java\nParam[] recipient = new Param[]{new Param(\"deviceId\", \"xxxxxxxxxxx\");\n\nJsonObject payload = io.ably.lib.util.JsonUtils.object()\n        .add(\"notification\", io.ably.lib.util.JsonUtils.object()\n            .add(\"title\", \"Hello from Ably!\")\n            .add(\"body\", \"Example push notification from Ably.\"))\n        .add(\"data\", io.ably.lib.util.JsonUtils.object()\n            .add(\"foo\", \"bar\")\n            .add(\"baz\", \"qux\")));\n\nrest.push.admin.publishAsync(recipient, payload, , new CompletionListener() {\n\t @Override\n\t public void onSuccess() {}\n \n\t @Override\n\t public void onError(ErrorInfo errorInfo) {\n\t\t // Handle error.\n\t }\n });\n```\n\n#### Activating a device and receiving notifications (Android only)\n\nSee https://www.ably.com/docs/general/push/activate-subscribe for detail.\nIn order to enable an app as a recipient of Ably push messages:\n\n- register your app with Firebase Cloud Messaging (FCM) and configure the FCM credentials in the app dashboard;\n- Implement a service extending [`FirebaseMessagingService`](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService) and ensure it is declared in your `AndroidManifest.xml`, as per [Firebase's guide: Edit your app manifest](https://firebase.google.com/docs/cloud-messaging/android/client#manifest);\n  - Override [`onNewToken`](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService#public-void-onnewtoken-string-token), and provide Ably with the registration token: `ActivationContext.getActivationContext(this).onNewRegistrationToken(RegistrationToken.Type.FCM, token);`. This method will be called whenever a new token is provided by Android.\n- Activate the device for push notifications:\n\n```java\nrealtime.setAndroidContext(context);\nrealtime.push.activate();\n```\n\n## Using Ably SDK Under a Proxy\n\nWhen working in environments where outbound internet access is restricted, such as behind a corporate proxy, the Ably SDK allows you to configure a proxy server for HTTP and WebSocket connections.\n\n### Add the Required Dependency\n\nYou need to use **OkHttp** library for making HTTP calls and WebSocket connections in the Ably SDK to get proxy support both for your Rest and Realtime clients.\n\nAdd the following dependency to your `build.gradle` file:\n\n```groovy\ndependencies {\n    runtimeOnly(\"io.ably:network-client-okhttp:1.2.52\")\n}\n```\n\n### Configure Proxy Settings\n\nAfter adding the required OkHttp dependency, you need to configure the proxy settings for your Ably client. This can be done by setting the proxy options in the `ClientOptions` object when you instantiate the Ably SDK.\n\nHere’s an example of how to configure and use a proxy:\n\n#### Java Example\n\n```java\nimport io.ably.lib.realtime.AblyRealtime;\nimport io.ably.lib.rest.AblyRest;\nimport io.ably.lib.transport.Defaults;\nimport io.ably.lib.types.ClientOptions;\nimport io.ably.lib.types.ProxyOptions;\nimport io.ably.lib.http.HttpAuth;\n\npublic class AblyWithProxy {\n    public static void main(String[] args) throws Exception {\n        // Configure Ably Client options\n        ClientOptions options = new ClientOptions();\n        \n        // Setup proxy settings\n        ProxyOptions proxy = new ProxyOptions();\n        proxy.host = \"your-proxy-host\";  // Replace with your proxy host\n        proxy.port = 8080;               // Replace with your proxy port\n        \n        // Optional: If the proxy requires authentication\n        proxy.username = \"your-username\";  // Replace with proxy username\n        proxy.password = \"your-password\";  // Replace with proxy password\n        proxy.prefAuthType = HttpAuth.Type.BASIC;  // Choose your preferred authentication type (e.g., BASIC or DIGEST)\n\n        // Attach the proxy settings to the client options\n        options.proxy = proxy;\n\n        // Create an instance of Ably using the configured options\n        AblyRest ably = new AblyRest(options);\n\n        // Alternatively, for real-time connections\n        AblyRealtime ablyRealtime = new AblyRealtime(options);\n\n        // Use the Ably client as usual\n    }\n}\n```\n\n## Resources\n\nVisit https://www.ably.com/docs for a complete API reference and more examples.\n\n### Example projects:\n\n- [Ably Asset Tracking SDKs for Android](https://github.com/ably/ably-asset-tracking-android/blob/main/README.md#useful-resources)\n- [Chat app using Spring Boot + Auth0 + Ably](https://github.com/ably-labs/spring-boot-auth0)\n- [Spring + Ably Pub/Sub Demo with a Collaborative TODO list](https://github.com/ably-labs/ably-spring-pubsub)\n\n## Requirements\n\nFor Java, JRE 8 or later is required. Note that the [Java Unlimited JCE extensions](https://www.oracle.com/uk/java/technologies/javase-jce8-downloads.html) must be installed in the Java runtime environment.\n\nFor Android, 4.4 KitKat (API level 19) or later is required.\n\n## Support, feedback and troubleshooting\n\nPlease visit http://support.ably.io/ for access to our knowledgebase and to ask for any assistance.\n\nYou can also view the [community reported Github issues](https://github.com/ably/ably-java/issues).\n\nTo see what has changed in recent versions of Bundler, see the [CHANGELOG](CHANGELOG.md).\n\n## Contributing\n\nFor guidance on how to contribute to this project, see [CONTRIBUTING.md](CONTRIBUTING.md).\n","funding_links":[],"categories":["进程间通信"],"sub_categories":["Spring Cloud框架"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fably-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fably%2Fably-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fably-java/lists"}