# Server Libraries Server libraries for using the Airship REST API. # Airship Java Library > Java library for using Airship's messaging platform and related features.## Resources - [Github Repo](https://github.com/urbanairship/java-library) - [Javadocs](https://www.airship.com/docs/reference/libraries/java/latest/) - [Airship API Reference](https://www.airship.com/docs/developer/rest-api/ua/) ## Installation You can install the Java Library with Maven or manually. ### Maven Add the library using Maven by adding the following lines to your pom.xml: ```xml com.urbanairship java-client VERSION ``` ### Manual To install the Java Library manually, clone the repository, run mvn package, and add the jar. The docs can also be built. Clone the Java Library repo, and build the jar: `mvn package` Add the jar, replacing 'VERSION' with your desired version number located at a path similar to: `target/java-client-VERSION.jar` If you would like a copy of the javadocs, use: `mvn javadoc:javadoc` ## Logging Add log4j to your pom.xml: **Add log4j to pom.xml** ```xml org.slf4j slf4j-log4j12 VERSION log4j log4j VERSION ``` Logging is done using the [Simple Logging Facade for Java](https://www.slf4j.org/). Using the logging facade allows for flexibility in logging choices. For example, to use log4j, you would add the following to your pom.xml: **Add log4j as log handler** ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.log4j.BasicConfigurator; Logger logger = LoggerFactory.getLogger("identifier"); // Use any configuration you need. BasicConfigurator.configure(); logger.debug("Log all the things!"); ``` Note the logging framework plus the adapter. For more info, see the [Simple Logging Facade documentation](https://www.slf4j.org/manual.html). Simply add the log handler of your choice. ## Getting Started ### Setting up an Airship Client > The following is the minimum-viable UrbanAirshipClient configuration: **Basic client configuration** ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("your-app-key-here") .setSecret("your-app-secret-here") .build(); ``` The UrbanAirshipClient handles the interaction between the client and the API. The client will throw an exception if there is an issue with the request, or if it is improperly configured. ### Connecting to European Server > Connecting to European Server: **Connect to European server** ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("your-app-key-here") .setSecret("your-app-secret-here") .setUseEuropeanSite(true) .build(); ``` ### Create a Request > Creating a request to the push API: **Create push request** ```java PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.iosChannel("ios_channel")) .setNotification(Notifications.alert("Here's a push!")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .build(); PushRequest request = PushRequest.newRequest(payload); ``` Next, you are going to create a request. ### Send the Request > Executing the push request: **Execute push request** ```java Response response = null; try { response = client.execute(request); logger.debug(String.format("Response %s", response.toString())); } catch (IOException e) { logger.error("IOException in API request " + e.getMessage()); } ``` Once you have created a request, you pass it to be executed in the client created earlier. ## The Airship Client The `UrbanAirshipClient` class handles requests to the Airship Engage API. This document covers the various configuration options, along with different methods for executing requests within the client. `UrbanAirshipClient` sets `AsyncRequestClient` as the underlying HTTP client by default for basic configurations. The `AsyncRequestClient` can be configured or a different HTTP client can be implemented by extending the `RequestCleint` interface. ### Configuration > Minimum-viable UrbanAirshipClient config **Basic client configuration** ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("your-app-key-here") .setSecret("your-app-secret-here") .build(); ``` As shown in the [Getting Started Guide](#getting-started), the minimum-viable UrbanAirshipClient client configuration requires an app key and a master secret. In the following sections, we’ll explore some of the additional client configuration options available. #### Client With Proxy > Setting the client proxy: **Configuring a proxy** ```java Realm realm = new Realm.Builder("user", "password") .setScheme(Realm.AuthScheme.BASIC) .build(); ProxyServer proxyServer = new ProxyServer.Builder("test.urbanairship.com", 8080) .setRealm(realm) .build(); AsyncRequestClient asyncRequestClient = AsyncRequestClient.newBuilder() .setProxyServer(proxyServer) .build(); UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("key") .setSecret("secret") .setClient(asyncRequestClient) .build(); ``` Optionally, a client can be created with proxy server support.           #### Client With HTTP Parameter Settings > Set HTTP parameters: **Set HTTP parameters** ```java DefaultAsyncHttpClientConfig.Builder clientConfigBuilder = new DefaultAsyncHttpClientConfig.Builder() .setConnectTimeout(20); AsyncRequestClient asyncRequestClient = AsyncRequestClient.newBuilder() .setClientConfigBuilder(clientConfigBuilder) .build(); UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("key") .setSecret("secret") .setClient(asyncRequestClient) .build(); ``` A client can also be created with the option to set any of the HTTP parameters configurable through the [Async HTTP client](https://static.javadoc.io/org.asynchttpclient/async-http-client/2.0.38/org/asynchttpclient/DefaultAsyncHttpClientConfig.Builder.html), such as the protocol and connection parameters, by passing in a `DefaultAsyncHttpClientConfig.Builder`. In the example, the connection timeout is set to be 20 ms, thus overriding the default settings as infinite timeouts.   #### Client with Custom Retry Logic You may optionally specify a custom retry predicate. This predicate dictates how the client responds to failure, i.e., when should the client retry a failed request. The default retry predicate will retry all requests that return responses with status codes of 500 or higher, assuming they are not POST requests. We avoid retrying POST requests in order to prevent duplicates (e.g., retrying a push request may result in duplicate pushes). Requests are retried a maximum of 10 times, with an exponentially-increasing backoff period between each attempt. > Configure the Predicate to retry: **Configure retries** ```java Predicate retryPredicate = new Predicate() { @Override public boolean apply(FilterContext input) { return input.getResponseStatus().getStatusCode() >= 500; } }; ``` In the example, we create a custom predicate that will retry all requests that return responses with status codes of 500 or greater. Unlike the default retry predicated, this predicate will retry POST requests.   > Set the Predicate to retry: **Set to retry** ```java AsyncRequestClient asyncRequestClient = AsyncRequestClient.newBuilder() .setRetryPredicate(retryPredicate) .setMaxRetries(20) .build(); UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("key") .setSecret("secret") .setClient(asyncRequestClient) .build(); ``` We now configure an UrbanAirshipClient to use the above retryPredicate. We also increase the max number of retry attempts from 10 to 20. ### Executing Requests > UrbanAirshipClient different modes of request execution: **Different ways of executing requests** ```java execute(Request request) execute(Request request, ResponseCallback callback) executeAsync(Request request) executeAsync(Request request, ResponseCallback callback) ``` Once you have a client configured and some sort of request created, the UrbanAirshipClient class supports four different modes of request execution.   #### Making Async Requests > Initiate a non-blocking call: **Initiate a non-blocking call** ```java // Non-blocking request Future futureResponse = client.executeAsync(request); // Do other stuff... // Retrieve your response after doing stuff. Response response = futureResponse.get(); ``` Use the executeAsync(..) method to initiate a non-blocking call to the Airship API.   #### Response Callbacks > Setting ResponseCallback: **Setting a Response Callback** ```java ResponseCallback callback = new ResponseCallback() { @Override public void completed(Response response) { // Logic specifying what to do upon request completion. doSomething(response) } @Override public void error(Throwable throwable) { // Logic specifying what to do if the request fails. doSomethingElse(throwable) } }; ``` Both the execute and executeAsync methods accept an optional ResponseCallback argument. Below, we define a callback that executes the `doSomething(...)` function once a request completes, and the `doSomethingElse(...)` function if the request fails.       > Example (executeAsync): **Example of an executeAsync request** ```java // Start the request execution. Once the request has completed (or thrown an error), // the appropriate callback function will be triggered. ``executeAsync`` is non-blocking, // so you can do other stuff while you wait for the callback to get triggered. Future response = client.executeAsync(request, callback) // Do other stuff... ``` We can use this callback with either execute or executeAsync: > Example (execute): **Example of an execute request** ```java // Start the request execution . Once the request has completed (or thrown an error), // the appropriate callback function will be triggered. ``execute`` is blocking, so // you must wait for the request to complete (or fail), after which the callback is triggered // and the Response<..> is returned. Response response = client.execute(request, callback) ```         #### Exceptions > Handling exceptions in the ResponseCallback: **ResponseCallback exception handling** ```java ResponseCallback callback = new ResponseCallback() { @Override public void completed(Response response) { // Logic specifying what to do upon request completion. doSomething(response) } @Override public void error(Throwable throwable) { if (throwable instanceof ClientException) { // Handle a 4xx response } else if (throwable instance of ServerException) // Handle a 5xx response } else { // Handle any other failure } } }; ``` The client will throw different exceptions depending on mode of execution. If you are not using a callback, all exceptions present as RuntimeExceptions. If you choose to use a callback, you can customize the error method to distinguish between ClientExceptions (4xx responses), ServerExceptions (5xx responses), and any other potential failures. ## API Endpoint examples ### Push The PushPayload has three components: * Audience and Selectors * Notifications * Device Types The first is the Audience. The audience is composed of Selectors, which can be compound or atomic (not compound). Selectors provide logical combinations of AND, OR, and NOT. #### Audience and Selectors > Send to your audience with kittens tag: **Send to a tag** ```java Selectors.tag("kittens"); ``` The Selectors and DeviceType classes provide factory methods that can be used together to create an Audience Selector. > A more complex audience query: **Complex audience example** ```java Selector andSelector = Selectors.and(Selectors.tag("puppies"), Selectors.tag("kittens")); Selector notSelector = Selectors.not(Selectors.tag("fish")); Selector compound = Selectors.or(andSelector, notSelector); ``` More complex logic is possible. #### Notifications > An example of an iOS notification implementing expiry and interactive notifications: **Example send to iOS with expiry and interactive features** ```java PushExpiry expiry = PushExpiry.newBuilder() .setExpirySeconds(3600) .build(); Interactive interactive = Interactive.newBuilder() .setType("ua_yes_no_foreground") .setButtonActions(ImmutableMap.of( "yes", Actions.newBuilder() .addTags(new AddTagAction(TagActionData.single("tag1"))) .build(), "no", Actions.newBuilder() .addTags(new AddTagAction(TagActionData.single("tag2"))) .build())) .build(); IOSDevicePayload iosPayload = IOSDevicePayload.newBuilder() .setAlert("alert") .setExpiry(expiry) .setInteractive(interactive) .build(); PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.iosChannel("9c36e8c7-5a73-47c0-9716-99fd3d4197d5")) .setNotification(Notifications.notification(iosPayload)) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .build(); ``` Notifications are the second part of the PushPayload. Notifications are configured for each type of device you would like to send a message to. A Notification for an iOS device contains options for alert, badge, sound, content_available, extra, expiry, priority, category, interactive, etc. Other platforms, e.g., Android, may offer different configurations based on available features. > An example of an iOS notification implementing global attributes personalization: **Global attributes example** ```java ArrayList productsList = new ArrayList(); ​ HashMap mMap = new HashMap(); mMap.put("id", 1); mMap.put("name", "New Line Sneakers"); mMap.put("price","79.95"); productsList.add(mMap); ​ mMap = new HashMap(); mMap.put("id", 2); mMap.put("name","Old Line Sneakers"); mMap.put("price","59.95"); productsList.add(mMap); ​ IOSDevicePayload iosPayload = IOSDevicePayload.newBuilder() .setAlert("Hi from Airship!{{#if super_sale }} We're having a sale on {{ products.0.name }}!{{/if}}") .addExtraEntry("url","http://www.urbanairship.com") .build(); ​ PushOptions myOptions = PushOptions.newBuilder() .setPersonalization(true) .build(); ​ PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.or(Selectors.iosChannel("9c36e8c7-5a73-47c0-9716-99fd3d4197d5"), Selectors.tags("sports","entertainment"))) .setNotification(Notifications.notification(iosPayload)) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .addGlobalAttributes("products", productsList) .addGlobalAttributes("super_sale",true) .setPushOptions(myOptions) .build(); ``` > An example of an iOS notification implementing media attachment and some specific iOS options: **Media attachment and special iOS options example** ```java IOSAlertData iosAlert = IOSAlertData.newBuilder() .setTitle("Kevin Gausman Throws a Perfect Game") .setBody("Kevin Gausman stymies the Houston Astros for San Francisco's second perfect game in franchise history.") .setSummaryArg("San Francisco Giants") .setSummaryArgCount(1) .build(); IOSMediaContent iosMediaContent = IOSMediaContent.newBuilder() .setBody("Kevin Gausman") .setBody("Gausman strikes out Justin Turner") .build(); IOSMediaOptions iosMediaOptions = IOSMediaOptions.newBuilder() .setCrop(Crop.newBuilder() .setHeight(BigDecimal.valueOf(0.5)) .setWidth(BigDecimal.valueOf(0.5)) .setX(BigDecimal.valueOf(0.25)) .setY(BigDecimal.valueOf(0.25)) .build()) .setTime(15) .build(); MediaAttachment mediaAttachment = MediaAttachment.newBuilder() .setContent(iosMediaContent) .setOptions(iosMediaOptions) .setUrl("https://media.example.com/media/6nJmrhlu4aL1m/giphy.gif") .build(); IOSDevicePayload iOSPayload = IOSDevicePayload.newBuilder() .setThreadId("sfGiants_news") .setAlert(iosAlert) .setRelevanceScore(1.0) .setIosInterruptionLevel(IOSInterruptionLevel.PASSIVE) .setSoundData(IOSSoundData.newBuilder().setName("strike-call").build()) .setMediaAttachment(mediaAttachment) .setMutableContent(true) .build(); PushPayload pushPayload = PushPayload.newBuilder() .setAudience(Selectors.all()) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .setNotification(Notifications.notification(iOSPayload)) .build(); ```         #### Device Types > Here’s an example of setting the device types to iOS and Android: **Setting device types to target** ```java DeviceTypeData deviceTypeData = DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID); ``` The final part of the PushPayload is DeviceTypes, which defines the platform you’re sending to, e.g., iOS or Android. Messages can be segregated by device types. Set the device types you want to send to using a DeviceTypeData object. ### Schedules #### Create a Scheduled Notification > Scheduling a push notification: **Schedule a push** ```java SchedulePayload schedulePayload = SchedulePayload.newBuilder() .setName("Morning People") .setSchedule(Schedule.newBuilder() .setScheduledTimestamp(DateTime.parse("2020-06-03T09:15:00Z")) .build()) .setPushPayload(PushPayload.newBuilder() .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setNotification(Notifications.alert("Good Day Sunshine")) .setAudience(Selectors.tag("earlyBirds")) .build()) .build(); ScheduleRequest scheduleRequest = ScheduleRequest.newRequest(schedulePayload); Response response = client.execute(scheduleRequest); ``` You can use the `ScheduleRequest.newRequest()` method to create a scheduled notification.       #### Update a Schedule > Updating a scheduled notification: **Update a scheduled push** ```java SchedulePayload schedulePayload = SchedulePayload.newBuilder() .setName("I would like to subscribe to your newsletter") .setSchedule(Schedule.newBuilder() .setScheduledTimestamp(DateTime.parse("2020-04-01T18:45:00Z")) .build()) .setPushPayload(PushPayload.newBuilder() .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setNotification(Notifications.alert("Check your inbox!")) .setAudience(Selectors.tag("intriguing")) .build()) .build(); ScheduleRequest scheduleRequest = ScheduleRequest.newUpdateRequest(schedulePayload, "5cde3564-ead8-9743-63af-821e12337812"); Response response = client.execute(scheduleRequest); ``` You can use the `ScheduleRequest.newUpdateRequest( "")` method to update a scheduled notification.       #### Lookup Schedule > Looking up a scheduled notification: **Look up a scheduled push** ```java ScheduleListingRequest request = ScheduleListingRequest.newRequest("5cde3564-ead8-9743-63af-821e12337812"); Response response = client.execute(request); SchedulePayloadResponse schedule = response.getBody().get().getSchedules().get(0); // Get the schedule's name Optional name = schedule.getName(); // Get the push IDs Set pushIds = schedule.getPushIds(); // Get the scheduled time Schedule sched = schedule.getSchedule(); // Get the associated push payload PushPayload payload = schedule.getPushPayload(); // Get the URL Optional url = schedule.getUrl(); ``` To lookup a schedule, use the `ScheduleListingRequest.newRequest("")` method.       #### List Schedules > List all scheduled notifications: **List scheduled pushes** ```java ScheduleListingRequest request = ScheduleListingRequest.newRequest(); Response response = client.execute(request); // Get the list of schedules List schedules = response.getBody().get().getSchedules(); ``` To view a list of all created schedules, use the `ScheduleListingRequest.newRequest()` method. #### Delete Schedule > Delete schedule request: **Delete a scheduled push** ```java ScheduleDeleteRequest request = ScheduleDeleteRequest.newRequest("schedule_1234"); Response response = client.execute(request); ``` To delete a schedule, use the `ScheduleDeleteRequest.newRequest("")` method. ### A/B Tests #### Create A/B Tests > Create an A/B Test with a schedule time: **Schedule an A/B test** ```java Schedule schedule = Schedule.newBuilder() .setScheduledTimestamp(DateTime.now().plusDays(1)) .build(); Variant variantOne = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Hello there!") .build() ) .build()) .setSchedule(schedule) .build(); Variant variantTwo = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Boogaloo") .build() ) .build()) .setSchedule(schedule) .build(); Experiment experiment = Experiment.newBuilder() .setName("Another test") .setDescription("Its a test!") .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .setAudience(Selectors.namedUser("NamedUserID")) .addVariant(variantOne) .addVariant(variantTwo) .build(); ExperimentRequest request = ExperimentRequest.newRequest(experiment); Response response = client.execute(request); ``` To create an A/B Test, use the `ExperimentRequest.newRequest()` method.                         #### Delete A/B Tests > Delete a scheduled A/B Test: **Delete a scheduled A/B test** ```java ExperimentDeleteRequest experimentDeleteRequest = ExperimentDeleteRequest.newRequest("experimentId"); Response response = client.execute(experimentDeleteRequest); ``` To delete a scheduled A/B Test, use the `ExperimentDeleteRequest.newRequest()` method. Note that experiments can only be deleted before they start. ### Personalization #### Create Template > Create a template: **Create a template** ```java TemplateVariable titleVariable = TemplateVariable.newBuilder() .setKey("TITLE") .setName("Title") .setDescription("e.g. Mr, Ms, Dr, etc") .setDefaultValue("") .build(); TemplateVariable firstNameVariable = TemplateVariable.newBuilder() .setKey("FIRST_NAME") .setName("First Name") .setDescription("Given name") .setDefaultValue(null) .build(); TemplateVariable lastNameVariable = TemplateVariable.newBuilder() .setKey("LAST_NAME") .setName("Last Name") .setDescription("Family name") .setDefaultValue("") .build(); PartialPushPayload partialPushPayload = PartialPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Hello {{TITLE}} {{FIRST_NAME}} {{LAST_NAME}}, welcome to our loyalty program!") .build() ) .build(); TemplateRequest request = TemplateRequest.newRequest() .setName("Template Name") .setDescription("A description") .addVariable(titleVariable) .addVariable(firstNameVariable) .addVariable(lastNameVariable) .setPush(partialPushPayload); Response response = client.execute(request); ``` To create a template, use the `TemplateRequest.newRequest()` method.                         #### Update Template > Update an existing template: **Update a template** ```java PartialPushPayload partialPushPayload = PartialPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Hello {{FIRST_NAME}} {{LAST_NAME}}, this is a test!") .build() ) .build(); TemplateRequest request = TemplateRequest.newRequest(UUID.randomUUID().toString()) .setName("your-template-name") .setPush(partialPushPayload); Response response = client.execute(request); ``` To update a template, use the `TemplateRequest.newRequest()` method.       #### Push to Template > In the example below, we push to the template we created in the Create Template section: **Send a push using a template** ```java TemplatePushPayload payload = TemplatePushPayload.newBuilder() .setAudience(Selectors.namedUser("named-user")) .setDeviceTypes(DeviceTypeData.of(DeviceType.ANDROID)) .setMergeData(TemplateSelector.newBuilder() .setTemplateId("template-id-123") .addSubstitution("FIRST_NAME", "James") .addSubstitution("LAST_NAME", "Brown") .addSubstitution("TITLE", "Mr.") .build()) .build(); TemplatePushRequest request = TemplatePushRequest.newRequest() .addTemplatePushPayload(payload); Response response = client.execute(request); ``` To push to a template, use the `TemplatePushRequest.newRequest()` method.           #### Template Lookup > Template lookup: **Look up a template** ```java TemplateListingRequest request = TemplateListingRequest.newRequest("template-id"); Response response = client.execute(request); ``` To look up a template, use the `TemplateListingRequest.newRequest("template-id")` method. #### Template Listing > List all Templates: **List templates** ```java TemplateListingRequest request = TemplateListingRequest.newRequest(); Response response = client.execute(request); ``` To list all templates, use the `TemplateListingRequest.newRequest()` method: #### Delete Template > Delete a Template: **Delete a template** ```java TemplateDeleteRequest request = TemplateDeleteRequest.newRequest("template-id"); Response response = client.execute(request); ``` To delete a template, use the `TemplateDeleteRequest.newRequest("template-id")` method. ## Audience Management ### Channels #### Lookup Channel > Look up an individual channel: **Look up a channel** ```java ChannelRequest request = ChannelRequest.newRequest("channel_id_123"); Response response = client.execute(request); ChannelView channel = response.getBody().get().getChannelView().get(); // The channel ID String channelId = channel.getChannelId(); // The channel type -- one of IOS, ANDROID, or ADM String channelType = channel.getChannelType(); // Whether the channel is installed or not boolean installed = channel.isInstalled(); // Whether the channel is opted in to push or not boolean optedIn = channel.isOptIn(); // Whether background push is enabled on the device Optional background = channel.getBackground(); // The push address associated with the channel Optional pushAddress = channel.getPushAddress(); // When the channel was created DateTime created = channel.getCreated(); // The date at which the channel was last registered DateTime lastRegistration = channel.getLastRegistration(); // The alias (potentially) associated with the channel Optional alias = channel.getAlias(); // The tags associated with the channel ImmutableSet tags = channel.getTags(); // The tag groups associated with the channel ImmutableMap> tagGroups = channel.getTagGroups(); // An IosSettings object Optional iosSettings = channel.getIosSettings(); ``` To lookup a specific channel, use the `ChannelRequest.newRequest("")` method.                   #### List Channels > List all channels: **List channels** ```java ChannelRequest request = ChannelRequest.newRequest(); Response response = client.execute(request); ChannelView channels = response.getBody().get().getChannelView().get(); ``` To list all channels, use the `ChannelRequest.newRequest()` method. ### Named Users #### Associate Named User > Associate channel to named user: **Associate a channel to a named user** ```java NamedUserRequest request = NamedUserRequest.newAssociationRequest() .setChannel("ee4b5101-164c-485c-ad91-68b1d3d753cc", ChannelType.IOS) .setNamedUserId("id-1234"); Response response = client.execute(request); ``` To associate channels to a Named User, use the NamedUserRequest class.   #### Disassociate Named User > Disassociate channel from named user: **Disassociate a channel from a named user** ```java NamedUserRequest request = NamedUserRequest.newDisassociationRequest() .setChannel("0ab7d6f0-0f61-4963-afe0-5ef53735b00d", ChannelType.ANDROID); Response response = client.execute(request); ``` To disassociate channels from a Named User, use the NamedUserRequest class. #### Look up a Named User > Look up a named user: **Look up a named user** ```java NamedUserListingRequest request = NamedUserListingRequest.newRequest("id-1234"); Response response = client.execute(request); NamedUserView namedUser = response.getBody().get().getNamedUserView().get(); // The named user ID String namedUserId = namedUser.getNamedUserId(); // Map of tag groups and the associated sets of tags ImmutableMap> namedUserTags = namedUser.getNamedUserTags(); // All channel objects associated with the named user ImmutableSet channelViews = namedUser.getChannelViews(); ``` To lookup a named user, use the `NamedUserListRequest.newRequest("")` method.     #### List Named Users > List named users: **List named users** ```java NamedUserListingRequest request = NamedUserListingRequest.newRequest(); Response response = client.execute(request); ImmutableList namedUsers = response.getBody().get().getNamedUserViews().get(); ``` To list named users, use the `NamedUserListRequest.newRequest()` method. ### Tags See: [Tags: Named Users](#add-remove-tags-from-named-users) #### Add/Remove Tags From Channel > Channel Tags: **Set up a channel tag request** ```java Set tags = new HashSet(); tags.add("loyalty"); tags.add("platinum"); tags.add("sports"); Set remove = new HashSet(); tags.add("gold"); tags.add("news"); ChannelTagRequest request = ChannelTagRequest.newRequest() .addIOSChannels("56071f7c-921f-4981-9568-b5f7cef427cd", "a74897b2-3ff3-4741-8b69-1d739fc3830f") .addAndroidChannel("ecf68576-c7ac-48cc-9aaa-94b63e6dccda") .addTags("device", tags) .removeTags("device", remove); Response response = client.execute(request); ``` To add tags use the ChannelTagRequest class. In the following example, we add the tags loyalty, platinum, and sports, and remove the tags gold and news.         #### Add/Remove Tags From Named Users To execute tag operations on a named user, use the NamedUserTagRequest class. > Add Tags: **Add tags** ```java Set tags = new HashSet(); tags.add("loyalty"); tags.add("platinum"); tags.add("sports"); NamedUserTagRequest request = NamedUserTagRequest.newRequest() .addNamedUsers("user-1", "user-2", "user-3") .addTags("device", tags); Response response = client.execute(request); ``` The `addTags("", )` method is used for adding tags.       > Remove Tags: **Remove tags** ```java Set tags = new HashSet(); tags.add("loyalty"); tags.add("platinum"); tags.add("sports"); NamedUserTagRequest request = NamedUserTagRequest.newRequest() .addNamedUsers("user-1", "user-2", "user-3") .removeTags("device", tags); Response response = client.execute(request); ``` The `removeTags("", )` method is used for removing tags.       > Set Tags: **Set tags** ```java Set tags = new HashSet(); tags.add("loyalty"); tags.add("platinum"); tags.add("sports"); NamedUserTagRequest request = NamedUserTagRequest.newRequest() .addNamedUsers("user-1", "user-2", "user-3") .setTags("device", tags); Response response = client.execute(request); ``` The `setTags("", )` method is used to wipe the current set of tags on the device with the provided set. ### Segments #### Create Segment > Create a Segment: **Create a segment** ```java SegmentRequest request = SegmentRequest.newRequest(); // Define the segment criteria Selector andSelector = Selectors.tags("java", "lib"); Selector compound = Selectors.or(andSelector, Selectors.not(Selectors.tag("mfd"))); DateRange dateRange = Selectors.weeks(3); Selector location = Selectors.location("us_zip", "97214", dateRange); Selector locationCriteria = Selectors.or(compound, location); // Set the request criteria and display name, and execute the request. request.setCriteria(locationCriteria); request.setDisplayName("UAJavaLib"); Response response = client.execute(request); ``` To create a segment, use the `SegmentRequest.newRequest()` method.       #### Look up a Segment > Look up a Segment: **Look up a segment** ```java SegmentLookupRequest request = SegmentLookupRequest.newRequest(""); Response response = client.execute(request); // Get the segment criteria Selector criteria = response.getBody().get().getCriteria(); // Get the segment display name String displayName = response.getBody().get().getDisplayName(); ``` To get information on a particular segment, use the `SegmentLookupRequest.newRequest("")` method.   #### List Segments > List all Segments: **List segments** ```java SegmentListingRequest request = SegmentListingRequest.newRequest(); Response response = client.execute(request); // Get the first segment in the list SegmentListingView segment = response.getBody().get().getSegmentListingViews().get(0); // Get the segment display name String displayName = segment.getDisplayName(); // Get the segment ID String id = segment.getSegmentId(); ``` To get a list of all segments, use the `SegmentListingRequest.newRequest()` method.       #### Update Segment > Update a segment: **Update a segment** ```java SegmentRequest request = SegmentRequest.newUpdateRequest(""); // Define the segment criteria Selector andSelector = Selectors.tags("java", "lib"); Selector compound = Selectors.or(andSelector, Selectors.not(Selectors.tag("mfd"))); DateRange dateRange = Selectors.weeks(3); Selector location = Selectors.location("us_zip", "97214", dateRange); Selector locationCriteria = Selectors.or(compound, location); // Set the request criteria and display name, and execute the request. request.setCriteria(locationCriteria); request.setDisplayName("UAJavaLib"); Response response = client.execute(request); ``` To update a segment, use the `SegmentRequest.newUpdateRequest("")` method.     #### Delete Segment > Delete a segment: **Delete a segment** ```java SegmentDeleteRequest request = SegmentDeleteRequest.newRequest(""); Response response = client.execute(request); ``` To delete a segment, use the `SegmentDeleteRequest.newRequest("")` method. ### Static Lists #### Create Static List > Create a static list: **Create a static list** ```java StaticListRequest request = StaticListRequest.newRequest("platinum_members") .setDescription("Subscribers with platinum status.") .addExtra("cool", "extras") .addExtra("another", "extra"); Response response = client.execute(request); ``` To create a static list, use the `StaticListRequest.newRequest("")` method. #### Upload Static List > Upload a static list: **Upload a static list** ```java File dataDirectory = new File("src/data"); String filePath = dataDirectory.getAbsolutePath() + "/platinum.csv"; StaticListUploadRequest request = StaticListUploadRequest.newRequest("platinum_members", filePath); Response response = client.execute(request); ``` To upload a static list, use the `StaticListUploadRequest.newRequest("", "")` method. #### Download Static List > Download the CSV associated with a static list: **Download static list CSV** ```java StaticListDownloadRequest request = StaticListDownloadRequest.newRequest(""); Response response = client.execute(request); ``` To download the CSV associated with a static list, use the `StaticListDownloadRequest.newRequest("")` method.   > Direct the output to FileOutputStream: **Direct static list CSV download to FileOutputStream** ```java FileOutputStream fileOutputStream = new FileOutputStream(new File("list.csv")); StaticListDownloadRequest request = StaticListDownloadRequest.newRequest("") .setOutputStream(fileOutputStream); Response response = client.execute(request); ``` Optionally, you can direct the output to a FileOutputStream by using the setResponseFile setter.     > Download a Lifecycle list: **Download a lifecycle list** ```java StaticListDownloadRequest request = StaticListDownloadRequest.newRequest(LifecycleListType.UNINSTALLS_LAST_MONTH) .setOutputStream(fileOutputStream); Response response = client.execute(request); ``` You can also call the `StaticListDownloadRequest.newRequest()` method with one of the Lifecycle List types defined in the LifecycleListType enum. ## Reports ### Platform Statistics Optionally, you can direct the output to a FileOutputStream by using the setResponseFile setter. > Platform Statistic Reports: **Getting platform statistic reports** ```java DateTime start = new DateTime(2015, 10, 1, 12, 0, 0, 0); DateTime end = start.plus(Period.hours(48)); // App Opens Report PlatformStatsRequest appOpensRequest = PlatformStatsRequest.newRequest(PlatformStatsRequestType.APP_OPENS) .setStart(start) .setEnd(end) .setPrecision(Precision.HOURLY); // Time in App Report PlatformStatsRequest tiaRequest = PlatformStatsRequest.newRequest(PlatformStatsRequestType.TIME_IN_APP) .setStart(start) .setEnd(end) .setPrecision(Precision.HOURLY); // Opt-ins Report PlatformStatsRequest optInsRequest = PlatformStatsRequest.newRequest(PlatformStatsRequestType.OPT_INS) .setStart(start) .setEnd(end) .setPrecision(Precision.HOURLY); // Opt-outs Report PlatformStatsRequest optOutsRequest = PlatformStatsRequest.newRequest(PlatformStatsRequestType.OPT_OUTS) .setStart(start) .setEnd(end) .setPrecision(Precision.HOURLY); // Push Report PlatformStatsRequest pushSendsRequest = PlatformStatsRequest.newRequest(PlatformStatsRequestType.SENDS) .setStart(start) .setEnd(end) .setPrecision(Precision.HOURLY); Response appOpensResponse = client.execute(appOpensRequest); Response tiaResponse = client.execute(tiaRequest); Response optInsResponse = client.execute(optInsRequest); Response optOutsResponse = client.execute(optOutsRequest); Response pushSendsResponse = client.execute(pushSendsRequest); PlatformStats stats = appOpensResponse.getBody().get().getPlatformStatsObjects().get().get(0); // Get the number of iOS devices int ios = stats.getIos(); // Get the number of Android devices int android = stats.getAndroid(); // Get the time interval DateTime date = stats.getDate(); ``` The various reports that provide platform feedback are all handled by the PlatformStatsRequest class. This group of reports includes the App Opens Report, Time in App Report, Opt-ins Report, Opt-outs Report, and Push Reports. Each of the following requests requires a start date, end date, and precision. ### Individual Push Response Statistics > Individual Push Response Statistics request: **Get the push response statistics report** ```java PushInfoRequest request = PushInfoRequest.newRequest("ca15a452-ad5d-4bd9-95bb-e190eeba32cd"); Response response = client.execute(request); PushInfoResponse pushInfo = response.getBody().get(); // Number of sends int sends = pushInfo.getSends(); // Number of direct responses to the push int directResponses = pushInfo.getDirectResponses(); // When the push was sent DateTime date = pushInfo.getPushTime(); // The push type -- can be one of BROADCAST_PUSH, SCHEDULED_PUSH, TAG_PUSH, UNICAST_PUSH PushType type = pushInfo.getPushType(); // The unique identifier for the push UUID pushId = pushInfo.getPushId(); // The (optional) group ID Optional groupId = pushInfo.getGroupID(); ``` Use the `PushInfoRequest.newRequst("")` class to get information on a particular push id. ### Response Listing > Response Listing request: **Get the response listing report** ```java DateTime start = new DateTime(2015, 10, 1, 12, 0, 0, 0); DateTime end = start.plus(Period.hours(48)); PushListingRequest request = PushListingRequest.newRequest() .setStart(start) .setEnd(end) .setLimit(20); Response response = client.execute(request); // Get the first item in an array of push info responses. You can use all of the getters // listed in the "Individual Push Response Statistics" section. PushInfoResponse pushInfo = response.getBody().get().getPushInfoList().get().get(0); ``` The PushListingRequest class is used to make requests to the /api/reports/responses/list endpoint. ## Custom Events > Setting your bearer token: **Set up a bearer token** ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("your-app-key-here") .setSecret("your-app-secret-here") .setBearerToken("your-bearer-token-here") .build(); ``` You must set a bearer token on the UrbanAirshipClient for custom events requests. If only custom event requests are being made, the secret is optional. > Create a custom event: **Create a custom event** ```java // Airship channel identifier for the user who triggered the event. CustomEventUser customEventUser = CustomEventUser.newBuilder() .setCustomEventChannelType(CustomEventChannelType.ANDROID_CHANNEL) .setChannel("e393d28e-23b2-4a22-9ace-dc539a5b07a8") .build(); // The body object which describes the user action. CustomEventBody customEventBody = CustomEventBody.newBuilder() .setName("purchased") .setValue(new BigDecimal(120.49)) .setTransaction("886f53d4-3e0f-46d7-930e-c2792dac6e0a") .setInteractionId("your.store/us/en_us/pd/shoe/pid-11046546/pgid-10978234") .setInteractionType("url") .setSessionId("22404b07-3f8f-4e42-a4ff-a996c18fa9f1") .build(); // The date and time when the event occurred. DateTime occurred = new DateTime(2015, 5, 2, 2, 31, 22, DateTimeZone.UTC); CustomEventPayload customEventPayload = CustomEventPayload.newBuilder() .setCustomEventBody(customEventBody) .setCustomEventUser(customEventUser) .setOccurred(occurred) .build(); CustomEventRequest customEventRequest = CustomEventRequest.newRequest(customEventPayload); Response response = client.execute(customEventRequest); ``` To create a custom event, use the CustomEventRequest.newRequest() method: # Airship PHP Library > PHP library for using Airship's messaging platform and related features.## Resources - [GitHub](https://github.com/urbanairship/php-library2/) - [Packagist](https://packagist.org/packages/urbanairship/urbanairship) - [Airship API Reference](https://www.airship.com/docs/developer/rest-api/ua/) - [PHP Library API Reference](https://www.airship.com/docs/reference/libraries/php/latest) > **Important:** Airship is no longer actively developing this library but will respond to feature requests, issues, and pull requests submitted to the [Airship Support site](https://support.airship.com). This library provides sample code, and Airship makes no guarantees as to completeness or regularity of updates. ## Requirements - PHP >= 5.3 Dependencies - Composer - Httpful - Monolog - Development dependencies: PHPUnit ## Example usage **Basic usage example** ```php ", ""); try { $response = $airship->push() ->setAudience(P\iosChannel("Insert your iOS channel here!")) ->setNotification(P\notification("Hello from PHP")) ->setDeviceTypes(P\deviceTypes("ios")) ->send(); } catch (AirshipException $e) { print_r($e); } ``` # Airship Python Library > Python library for using Airship's messaging platform and related features.## Resources - [GitHub Repo](https://github.com/urbanairship/python-library/) - [Python Package Index (PyPI)](https://pypi.python.org/pypi/urbanairship) - [Airship API Reference](https://www.airship.com/docs/developer/rest-api/ua/) - [Python Library API Reference](https://www.airship.com/docs/reference/libraries/python/latest) ## Installation Using `pip`: ```bash pip install urbanairship ``` ## Using the library The library is intended to be used with the small footprint of a single import. To get started, import the package, and create an `Airship` object representing a single Airship application: ```python import urbanairship as ua client = ua.BasicAuthClient('', '') push = ua.Push(client) push.audience = ua.ios_channel('074e84a2-9ed9-4eee-9ca4-cc597bfdbef3') push.notification = ua.notification(ios=ua.ios(alert='Hello from Python', badge=1)) push.device_types = ua.device_types('ios') push.send() ``` The library uses [Requests](https://requests.kennethreitz.org/en/master/) for communication with the Airship API, providing connection pooling and strict SSL checking. The `Airship` object is threadsafe and can be instantiated once and reused in multiple threads. ## Logging `urbanairship` uses the standard logging module for integration into an application's existing logging. If you do not have logging configured otherwise, set it up in your application. **Set up logging** ```python import logging logging.basicConfig() ``` If you're having trouble with the Airship API, you can turn on verbose debug logging. **Turn on verbose logging** ```python logging.getLogger('urbanairship').setLevel(logging.DEBUG) ``` As of Python 2.7, `DeprecationWarning` warnings are silenced by default. To enable them, use the `warnings` module. **Turn on deprecation warnings** ```python import warnings warnings.simplefilter('default') ``` # Airship Ruby Library > Ruby library for using Airship's messaging platform and related features.## Resources - [GitHub Repo](https://github.com/urbanairship/ruby-library/) - [rubygems.org](https://rubygems.org/gems/urbanairship/) - [Airship API Reference](https://www.airship.com/docs/developer/rest-api/ua/) - [Ruby Library API Reference](https://www.airship.com/docs/reference/libraries/ruby/latest) ## Installation If you do not yet have the `bundler` gem, get it using: **Install Bundler** ```bash gem install bundler ``` Once you have the `bundler` gem, add this line to your application's Gemfile: **Install our gem** ```bash gem 'urbanairship' ``` And then execute: **Bundle** ```bash bundle ``` Or install it yourself as: **Alternative installation** ```bash gem install urbanairship ``` ## Configuration In your app initialization, you can do something like the following: **Example configuration** ```ruby require 'urbanairship' Urbanairship.configure do |config| config.server = 'api.asnapieu.com' config.oauth_server = 'oauth2.asnapieu.com' config.log_path = '/path/to/your/logfile' config.log_level = Logger::WARN config.timeout = 60 end ``` If you want to use a custom logger such as Rails.logger, you can do: **Custom logger** ```ruby require 'urbanairship' Urbanairship.configure do |config| config.custom_logger = Rails.logger config.log_level = Logger::WARN end ``` ### Available configurations Allowances per configuration: * log_path — Allows defining the folder where the log file will be created. The default is nil. * log_level — Allows defining the log level. Only messages at that level or higher will be printed. The default is INFO. * server — Allows defining the Airship server you want to use ("api.asnapieu.com" for EU or "api.asnapius.com" for US) * oauth_server — Allows defining the Airship OAuth server you want to use. Use `oauth2.asnapieu.com` for EU or `oauth2.asnapius.com` for US. * timeout — Allows defining the request timeout in seconds. The default is 5. ## Usage Broadcast to all devices: **Broadcast** ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key:'application_key', secret:'master_secret') p = airship.create_push p.audience = UA.all p.notification = UA.notification(alert: 'Hello') p.device_types = UA.device_types(['ios','android']) p.send_push ``` Basic tag push: **Tag push** ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key:'application_key', secret:'master_secret') p = airship.create_push p.audience = UA.tag('some_tag') p.notification = UA.notification(alert: 'Hello') p.device_types = UA.device_types(['ios','android']) p.send_push ``` ### Specify the Airship server used to make your requests By default, the request will be sent to server api.asnapius.com: **Default server with Basic auth** ```ruby require 'urbanairship' Urbanairship::Client.new(key:'application_key', secret:'master_secret') ``` You can change the server globally in the Urbanairship configuration: **Using a different server** ```ruby require 'urbanairship' Urbanairship.configure do |config| config.server = 'api.asnapieu.com' end Urbanairship::Client.new(key:'application_key', secret:'master_secret') # request will be sent to the 'api.asnapieu.com' server ``` ### Using Bearer Token auth **Bearer token authentication** ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key:'application_key', token:'token') # Then continue as you would otherwise ``` ### Using OAuth **OAuth** ```ruby require 'urbanairship' UA = Urbanairship app_key = 'application_key' oauth = UA::Oauth.new( client_id: 'client_id', key: app_key, assertion_private_key: 'your_private_key', scopes: ['psh', 'chn'], # Optional ip_addresses: ['23.74.131.15/22'], # Optional oauth_server: 'api.asnapieu.com' # Optional ) airship = UA::Client.new(key: app_key, oauth: oauth) # Then continue as you would otherwise ``` > **Note:** * You cannot use both OAuth and Bearer Token auth at the same time. > * OAuth cannot be used with the older `api.urbanairship.com` and `api.airship.eu` base URLs. See [Base URL](https://www.airship.com/docs/developer/rest-api/ua/introduction/#servers) and [OAuth](https://www.airship.com/docs/developer/rest-api/ua/operations/oauth/) in the *Airship API* reference. > * OAuth is not supported for all endpoints. See the [Airship API Authorization Reference](https://www.airship.com/docs/developer/rest-api/ua/api-auth-reference/).