//[[sdk:basics|Mobile SDK]]// ====== Android SDK Integration Manual ====== The Messangi Android library is designed to work in an automated way, that simplifies its inclusion in projects in development or already developed without affecting the main development cycle. The library is designed to work with a minimum API level of 15, so it works on more than 98% of current Android devices according to official statistics by Google. ===== Java version for SDK ===== The development of an application using this library requires **Java version 8**. To activate this, in the file **build.gradle (Module: app)** the field **compileOptions** must be added, it can be guided with the code below android { ... defaultConfig { .... } compileOptions { targetCompatibility 1.8 sourceCompatibility 1.8 } } If your project was working with Java 7 don’t worry, everything will continue working. This requirement optimizes the code produced by the Java Virtual Machine (JVM) to get a more efficient code. ===== Including Firebase and Messangi Libraries ===== Once the project is configured to compile using Java 8, the library can be included. Messangi library works along with Google's Firebase platform, in order to deliver pushes to all Android devices associated with the app. Messangi library is distributed through **JCenter**, so it is available to any developer who wants to use it. Add all dependencies in **build.gradle (Module: app)** as follows: ... android { ... } dependencies { ... implementation 'com.google.firebase:firebase-core:16.0.8' implementation 'com.google.firebase:firebase-messaging:17.3.4' implementation 'com.ogangi.messangi.android.sdk:messangisdk:5.2.2' implementation 'com.ogangi.messangi.android.sdk:messangi-push:5.2.2' ... } ... To configure the Firebase Cloud Messaging into your project, you need to perform a few basic tasks to prepare your Android Studio project. First, add rules to your root-level ''%%build.gradle%%'' file, to include the google-services plugin and the Google and JCenter repositories (check first if they’re not already included) buildscript { // ... dependencies { // ... classpath 'com.google.gms:google-services:4.3.1' // google-services plugin } } allprojects { // ... repositories { google() jcenter() // ... } } Then, in your module Gradle file (usually the ''%%app/build.gradle%%''), add the ''%%apply plugin%%'' line at the bottom of the file to enable the Gradle plugin: apply plugin: 'com.android.application' android { // ... } dependencies { // ... } // ADD THIS AT THE BOTTOM apply plugin: 'com.google.gms.google-services' ===== Firebase App integration ===== To add Firebase to your app you'll need a Firebase project and a Firebase configuration file for your app. - Create a Firebase project in the [[https://console.firebase.google.com/|Firebase console]], if you don't already have one. If you already have an existing Google project associated with your mobile app, click **Import Google Project**. Otherwise, click **Add project**. - Click **Add Firebase to your Android app** and follow the setup steps. If you’re importing an existing Google project, this may happen automatically and you can just [[http://support.google.com/firebase/answer/7015592|download the config file]]. - When prompted, enter your app’s package name. It's important to enter the package name that your app is using; this can only be set when you add an app to your Firebase project. - At the end, you’ll download a ''%%google-services.json%%'' file. You can [[http://support.google.com/firebase/answer/7015592|download this file]] again at any time. - If you haven’t done so already, copy that file into your project’s module folder, typically ''%%app/%%''. **Note:** If you have multiple build variants with different package names defined, each app must be added to your project in Firebase console. ==== Resources to share with us ==== To be able to send notifications through Firebase it is necessary to **share the Server Key and Sender ID** with the support team - Open a Firebase project previously created in the [[https://console.firebase.google.com/|Firebase console]]. - In the top left corner of the screen, click on the little cogwheel and select ''%%Project settings%%'' - On the new page, go to the ''%%Cloud Messaging%%'' tab. Your //Sender ID// and //Server key// are listed here. Please **send to our support team** the Server Key and the ''google-services.json'' file. ==== Messangi.xml file ==== The Support Team will send you back a file named **messangi.xml**, this must be added in the directory **src/main/res/values** of your app ===== Authentication (Optional) ===== The Messangi library initially provides an automatic user authentication method, this means that, when the application is started by the first time, it automatically creates an identifier for the device and for the user that make use of it. To access that information the class **MessangiInstanceId** has the following methods: // Get the device identifier MessangiInstanceId.getInstance().getDeviceID(); // Get the User identifier MessangiInstanceId.getInstance().getUserID(); // Get the time when user was created MessangiInstanceId.getInstance().getCreationTime(); However in some cases this is not enough and the developer wants to control life cycle of the user in application or use their own identifier. For these cases the library has the following methods: * Register User String userId = ...; MessangiApp.getInstance().login(userId); * Delete user registration (This will also remove all notifications, geofences and beacons registered in the device) MessangiApp.getInstance().logout(); * Register with another ID MessangiInstanceId.getInstance().resetUserId(); If you want to avoid the predefined behavior of generating a unique random identifier for your user and set it yourself using login method, you must modify the **auto_register** field to **false** in the **messangi.xml** configuration file. Finally, the developer can add an event listener to verify when the device is correctly registered and ready to receive push notifications. If it is ready when the listener is added, it will fire at once. MessangiInstanceId.getInstance().addOnDeviceReadyListener(() -> { // Device ready to receive push notifications }); If you don’t use any of these methods, the same system will receive push notifications making use of the autogenerated identifiers by the library. ===== PUSH Notifications ===== ==== Push Reception Library (Option 1) ==== If you use Messangi Push Library and need having information about the generation of the push token, you can use the class **MessangiInstanceId** and the following methods: // Get the last received push token (can be null) MessangiInstanceId.getInstance().getPushToken(); // Receives updates automatically when a token update occurs MessangiInstanceId.getInstance().addOnTokenRefreshListener(token -> { log.d("token_update" , token); }); If you already have Push Notifications Reception implemented in your application, the inclusion of this Library is not necessary. ==== Self Implementation (Option 2) ==== If you already have your own implementation for push reception or you want to do it by your own, we provide the following methods, which should be called by your application: * Create or update push token When the push token is created or updated, it must be notified to the library to keep it synchronized in the cloud. This is done by the following method: //Push Token Provided by Firebase Push Service String token = FirebaseInstanceId.getInstance().getToken(); MessangiInstanceId.getInstance().setPushToken(token); **MessangiInstanceId** is the class for managing the push token on the server in order to receive push notifications. * Process a Push Notification When a Messangi Campaign Manager sends a Push Event to the application, it has a special format designed to be interpreted by the Messangi Library. The class **MessangiEventManager** is used for processing these remote events. @Override public void onMessageReceived(RemoteMessage remoteMessage) { // Handle data payload of FCM messages. MessangiEvent event = MessangiEvent.newBuilder() .withId(remoteMessage.getMessageId()) .withType(remoteMessage.getMessageType()) .withFrom(remoteMessage.getFrom()) .withSendTime(remoteMessage.getSentTime()) .withData(remoteMessage.getData()) .build(); MessangiEventManager.onEventReceived(getApplicationContext(), event); } In the example above we show the method that receives messages from Firebase Cloud Messaging, if you want to use some other Push Service, you must also build a **MessangiEvent** and add the //payload// of the notification with the method //withData//. ==== Displaying the Notifications ==== === Messangi UI Library (Option 1) === The main Messangi Library processes, indexes and delivers notifications to the application that integrates it, but does not have tools to display notifications. For this purpose we provide Messangi UI Library, this library adds to your application the capability to show Messangi Notifications Events in devices' notification area. To add this library, simply add it **after** the main libraries, in the file **build.gradle (Module: app)** at level of **dependencies**. dependencies { ... implementation 'com.ogangi.messangi.android.sdk:messangisdk:5.2.2' implementation 'com.ogangi.messangi.android.sdk:messangi-push:5.2.2' implementation 'com.ogangi.messangi.android.sdk:messangi-ui:5.2.2' ... } This library is currently in active development, so in the next release we’ll provide more customization and configuration possibilities. === Broadcast Receiver (Option 2) === If you don’t want to use the previous library or want to control the visual representation of your notifications at a higher level, you can add a //Broadcast Receiver// to your application. For doing this you must create a class that extends BroadcastReceiver. The intent delivers to you a receiver, a json representation of the message. public class MessangiReceiver extends BroadcastReceiver { private static final String TAG = "MessangiReceiver"; public MessangiReceiver() { } @Override public void onReceive(Context context, Intent intent) { // The intent delivers a json representation of the push notification String json = intent.getStringExtra("message"); } } Then in the **AndroidManifest.xml** you must add the following **permission**: And also there, inside application tag, the reference to the broadcast receiver: Now you have all the necessary information to customize your notification as you prefer. ==== Notification handling ==== The Messangi Library maintains a virtual //inbox//, it stores all the notifications received by the library, to manipulate this inbox we provide the class **MessangiNotificationManager**. The class has the following methods: * List all notifications on the inbox MessangiNotificationManager.getInstances().getNotifications(); * Delete a single notification (you must have an instance of it previously) MessangiNotificationManager.getInstances().deleteNotification(notification); * Delete all notifications inside inbox MessangiNotificationManager.getInstances().clearNotifications(); * Force synchronization of notifications with the server MessangiNotificationManager.getInstances().syncronize(); If you want to add a listener that notifies you when a notification arrives, you can use this method (only works when the app is running): MessangiNotificationManager.getInstances() .addOnNotificationReceiveListener(message -> { Log.d("MESSAGE", message.toString()); }); The Campaign Manager can remotely remove notifications on the devices, so the removal process can be activated remotely by multiple triggers. ===== Location and Context Services ===== Android starting on version 6 (Marshmallow) adds a permissions policy that requires displaying a dialogue requesting permission to collect certain information from device sensors. For this reason if you want to use features such as Geofences, Geopush or obtain precise information regarding the location of the device, you must request the location permission, by adding it in your AndroidManifest.xml file: ... ... and using the following code: final int REQUEST_LOCATION = 99; if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { String[] permissions = new String[]{ android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION} ActivityCompat.requestPermissions(this, permissions, REQUEST_LOCATION); } For more information about permissions you can consult the [[https://developer.android.com/guide/topics/permissions/overview|official documentation]] ==== Location ==== If you want to receive updates of the location or configure the refresh rate using the Messangi Library, you can use the ''%%MessangiLocationManager%%'' class * Receive Location Updates MessangiLocationManager.getInstance() .addOnLocationUpdateListener(location -> { Log.d("LOCATION", location.toString()); }); * Get the last known location Location location = MessangiLocationManager.getInstance().getLastKnownLocation(); * Configure the location service // Element by Element MessangiLocationManager.getInstance().enableLocation(true); MessangiLocationManager.getInstance().setFasterInterval(30000); MessangiLocationManager.getInstance().setLocationPriority(1); MessangiLocationManager.getInstance().setLocationUpdateTime(60000); // Using a Configuration Object LocationOptions options = LocationOptions.newBuilder() .setEnable(true) .setFasterInterval(30000) .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) .setUpdateTime(60000) .build(); MessangiLocationManager .getInstance() .updateLocationOptions(options); ==== Geofences ==== The geofences are regions that trigger an action when are traversed. When the device detects this trigger, it sends a notification to the Campaign Manager so it produces some action configured on it, so it’s required to have data connection at the time the event is triggered. To make use of it, the library has the class ''%%MessangiGeofenceManager%%'' and with it you can call the following methods: * Get all the geographic regions that are being monitored. MessangiGeofenceManager.getInstances().getGeofences(); * Synchronize the information between the Campaign Manager and the Device. MessangiGeofenceManager.getInstances().synchronize(); * Restart monitoring of all regions MessangiGeofenceManager.getInstances().restartGeofences(); ==== Beacons ==== Beacons are devices that emit a signal around them in a small area that depends on the beacon itself. When the device detects this zone, it sends a notification to the Campaign Manager so that it produces some action configured on it, so it’s required have data connection at the time the event is triggered. For the management of these, the library provides the class ''%%MessangiBeaconManager%%'' with the following methods: * Get all Beacons that are being monitored MessangiBeaconManager.getInstance().getBeacons() * Get only the beacons based on Wifi technology MessangiBeaconManager.getInstance().getWifiBeacons() * Synchronize the information between the campaign manager and the device MessangiBeaconManager.getInstance().synchronize(); * Restart monitoring of all Beacons MessangiBeaconManager.getInstance().restartBeacons(); **Beacon** technology constantly checks the environment of the device, so it can have quite **strong battery costs**. For this reason we provide a complete set of functions that configure the device refresh policy itself, in such a way that each application is the one that decides the level of impact it will have in battery consumption. // Creating an instance power saver class can improve battery life by 60% by slowing down scans when your app is in the background. MessangiBeaconManager.getInstance().setPowerSaver(false); // Allows devices with API 21+ will use the Android L APIs to scan for beacons, below 21 API use old Android Way MessangiBeaconManager.getInstance().useNewBeaconScanner(true); // Allow the library to use a tracking cache MessangiBeaconManager.getInstance().useTrackingCache(true); // Set region exit period in milliseconds MessangiBeaconManager.getInstance().setRegionExitPeriod(30000); // Turns on/off saving the state of monitored regions to persistent storage so it is retained over app restarts. MessangiBeaconManager.getInstance().useRegionStatePersistence(true); // Enable or not automatically change between Background and Foreground modes. This method requires app restart. MessangiBeaconManager.getInstance().autoChangeScanMode(true); // This method notifies the beacon service that the application is either moving to background mode. MessangiBeaconManager.getInstance().scanInBackgroundMode(); // This method notifies the beacon service that the application is either moving to foreground mode. MessangiBeaconManager.getInstance().scanInForegroundMode(); /* * First parameter sets the duration in milliseconds of each Bluetooth LE scan cycle to look for beacons. * Second parameter sets the duration in milliseconds between each Bluetooth LE scan cycle to look for beacons. */ MessangiBeaconManager.getInstance().setForegroundPeriods(1500, 2000); /* * First parameter sets the duration in milliseconds of each Bluetooth LE scan cycle to look for beacons. * Second parameter sets the duration in milliseconds between each Bluetooth LE scan cycle to look for beacons. */ MessangiBeaconManager.getInstance().setBackgroundPeriods(5000,10000); ===== Analytics (Optional) ===== Events can be generated in the Analytics platform via the **MessangiAnalytics** class. Please note Messangi Library automatically captures some events and sends them to the Platform. You can access the **MessangiAnalytics** facility from any section of your app by using one of these methods: /* * This method adds any event you want to track on the platform. In the first parameter put the type, in the second a descriptive message and in the last a campaign name, this can be null. * The type is an enumeration class of the Messangi library, but the method is overloaded with a simple String type in case the programmer wishes to integrate his own events. */ MessangiAnalytics.getInstances().logEvent(eventType, message, campaignName); /* * This method informs a Crash in your application. In the first parameter put a descriptive message, in the second a campaign name and in the last the Exception raised. */ MessangiAnalytics.getInstances().crashEvent(message, campaignName, exception); These events will be shown along all the events being generated by the Library or the application itself in the corresponding dashboard. ^EventType ^Description ^ |INIT |App was opened | |ERROR |Error was raised | |PUSHRECEIVED |Text Push Arrive | |SUBSCRIBED_WORKSPACE |The user join a workspace | |UNSUBSCRIBED_WORKSPACE |The user leave a workspace | |SYNC_GEOFENCE |When Geofences finished the synchronization | |GEOFENCE_ENTER |Trigger a Geofence Enter | |GEOFENCE_ENTER_EXTRA_INFO|Contextual Device information on Enter | |GEOFENCE_EXIT |Trigger a Geofence Exit | |GEOFENCE_EXIT_EXTRA_INFO |Contextual Device information on Exit | |WIFI_BEACON_CONNECT |Trigger a Wifi Beacon Enter | |WIFI_BEACON_DISCONNECT |Trigger a Wifi Beacon Exit | |BEACON_ENTER |Trigger a BlueTooth Beacon Enter | |BEACON_EXIT |Trigger a BlueTooth Beacon Exit | |PUSH_TOKEN_REGISTERED |The user can start receiving Push on that device|