Overview
Mobibox android SDK is the Global solution for mobile advertising, tracking and in app subscriptions.
Mobibox SDK allows charging users in a clear and simple way. It doesn’t require users to have a credit card or bank account to subscribe to premium features of the application that integrates this SDK.
One of the most important features of our SDK is that we offer MSISDN detection solution.
When it is possible, the SDK will auto detect MSISDN and make it available to the host app.
According to the payment method (MT, MO, DCB...), users enter their cell phone number, receive a text message with a Pin Code or press a button to subscribe and then all virtual charges are automatically charged to the user’s cell phone bill (charging fees will be clearly communicated to users in the disclaimer).
In parallel, Mobibox SDK measures the effectiveness of the application promotion campaigns that integrates it by tracking the installs and in-app events (such as subscriptions and sign-ups) and see how many of these conversions are being driven by the advertising networks.
It is possible to tag any event in the application to be tracked as a conversion. Whenever users perform the tagged action, the event is recorded and can be viewed in campaign reports.
Basic Integration
Download SDK
Download Mobibox sdk 3.906 from below link
https://goo.gl/jCZLNi
Add Mobibox SDK to your android project
Goto File -> New -> New Module -> then select Import .JAR/.AAR Package
After that it will ask you for AAR path, so select the sdk path and click on finish.
Then it will take few second to add it on your project
Here you can see modules and you need to select host app like in screenshot
Then you need to click on Dependencies tab, you can see there list of dependencies
There you can see AAR file and you need to select it and click ok on dependency dialog then also click on ok on project structure dialog.
After that it will take few second to sync project.
After sync finish you need to open app level gradle file where you can see below line :
implementation project(':paymentsdk-3.906)
Additional Dependencies for the project
implementation 'com.android.support:multidex:1.0.2'
implementation 'io.branch.sdk.android:library:2.+'
implementation 'com.facebook.android:facebook-android-sdk:[4,5)'
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
implementation 'com.google.android.gms:play-services-analytics:12.0.1'
implementation 'com.google.android.gms:play-services-base:12.0.1'
implementation 'com.google.android.gms:play-services-identity:12.0.1'
implementation 'com.google.android.gms:play-services-auth:12.0.1'
implementation 'com.google.android.gms:play-services-auth-api-phone:12.0.1'
implementation 'com.google.code.gson:gson:2.4'
implementation 'com.adjust.sdk:adjust-android:4.12.4'
implementation 'com.android.installreferrer:installreferrer:1.0'
implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
implementation project(':paymentsdk-3.903')
In case if you are using proguard rules then you need to add below rules in proguard-rules file:
-dontwarn io.branch.**
-dontwarn javax.annotation.**
-keepattributes Exceptions
-dontwarn okhttp3.**
-keep class okhttp3.** { *; }
-dontwarn okio.**
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.ParametersAreNonnullByDefault
Add permissions
In the Package Explorer open the AndroidManifest.xml of your Android project and add the following permissions.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- SDK permissions -->
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- Only to be added if MO flow is supported -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
Add Intent filter to receive SMS
To support auto-detection of Pin code for DCB subscriptions, we need to be able to listen to incoming SMS. In order to do this, we will add a <receiver> to register a broadcast receiver to the manifest XML. We will also add an <intent-filter> to let Android know that we want to launch a specific class when an SMS comes in.
<receiver android:name="com.ma.paymentsdk.broadcast.MA_MessageReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Add Broadcast Receivers for tracking
Whenever your app is installed on a device, Android broadcasts an Intent containing the Google Play Install referrer. This is an important attribution value which must be passed into Mobibox SDK.
You'll need to configure a BroadcastReceiver which listens for this Intent. This can be done by adding receiver tag inside the application tag in your AndroidManifest.xml.
<!-- Branch install referrer tracking -->
<receiver android:name="io.branch.referral.InstallListener" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver
android:name="com.sample.sdk_integration.utilities.InstallReceiver"
android:exported="true" >
<intent-filter android:priority="1000">
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
Since your app contains SDK which needs to know about the Google Play Referrer, you should implement your own BroadcastReceiver. This custom BroadcastReceiver should extract the referrer from the Intent and pass it into each SDK like below:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.google.android.gms.analytics.CampaignTrackingReceiver;
import com.ma.paymentsdk.broadcast.MA_CampaignTrackingReceiver;
public class InstallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
new MA_CampaignTrackingReceiver().onReceive(context, intent);
// Google Analytics
new CampaignTrackingReceiver().onReceive(context, intent);
}
}
Basic Setup
a. Define set of keys and identifiers related to your app by adding the following meta-data tag inside the <application> element in AndroidManifest.xml.
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id" />
<meta-data android:name="com.ma.ServiceId" android:value="@string/serviceId"/>
<meta-data android:name="com.ma.ClientGuid" android:value="@string/ClientGuid"/>
<meta-data android:name="com.ma.ClientKey" android:value="@string/ClientKey"/>
<meta-data android:name="com.ma.AppToken" android:value="@string/appToken" />
<!-- Branch init -->
<meta-data android:name="io.branch.sdk.BranchKey" android:value="@string/branch_key_live" />
<meta-data android:name="io.branch.sdk.BranchKey.test" android:value="@string/branch_key_test" />
<!-- Branch testing (TestMode "true" to simulate fresh installs on dev environment) -->
<meta-data android:name="io.branch.sdk.TestMode" android:value="false" />
<!-- campaignId is used only in case of offline campaigns -->
<meta-data android:name="com.ma.Apk_CampaignId" android:value="@string/ApkCampaignid"/>
b. Fill in the values of your keys and identifiers in strings.xml file. (To be provided by MobileArts).
<string name="serviceId"></string>
<string name="ClientGuid"></string>
<string name="ClientKey"></string>
<string name="appToken"></string>
<string name="facebook_app_id"></string>
<string name="ApkCampaignid"></string>
<!-- Branch App Links -->
<string name="host_app_url"></string>
<string name="host_app_test_url"></string>
<string name="host_app_amazon_url"></string>
<string name="branch_key_live"></string>
<string name="branch_key_test"></string>
c. Inside the<application> element in AndroidManifest.xml, define the below activities used from Mobibox SDK (Subscription related activities).
<activity android:name=".SplashSceenActivity"
android:launchMode="singleTask"
android:hardwareAccelerated="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="mobilearts" android:host="open" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<!-- Branch App Links (optional) -->
<intent-filter android:autoVerify="true">
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https" android:host="@string/host_app_url" />
<data android:scheme="https" android:host="@string/host_app_test_url" />
<data android:scheme="https" android:host="@string/host_app_amazon_url" />
</intent-filter>
</activity>
<activity
android:name="com.ma.paymentsdk.MA_BillingActivity"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar.NoActionBar"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden" >
</activity>
<activity
android:name="com.ma.paymentsdk.SelectCountryActivity"
android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
android:screenOrientation="portrait"/>
We recommend using a global android Application class to initialize Branch. If you don't have one in your app already, follow these steps:
a. Create a class “GlobalApplication” that extends Application.
b. Open the AndroidManifest.xml file of your app and locate the <application> element.
c. Add the attribute android:name and set it to the name of your new application class
prefixed by a dot, so the manifest file is configured as:
<application
android:name=".GlobalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
tools:replace="icon,label,theme">
d. In your Application class find or create the onCreate method and add the following code to initialize the Branch.
import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
import io.branch.referral.Branch;
public class GlobalApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void onCreate() {
super.onCreate();
// Branch logging for debugging
Branch.enableLogging();
// Branch object initialization
Branch.getAutoInstance(this).enableFacebookAppLinkCheck();
}
}
Initialize the SDK
We recommend using a SplashActivity class to initialize Mobibox SDK.
a. We recommend using an Utility class to handle preferance and global funcations. If you don't have one in your app already, follow these steps:
1. Create a Class "Utility".
2. Add the following function on it.
public static void setDeeplinkUser(Context context, final boolean value){
// Save boolean value on preference
PreferenceData.setBooleanPrefs(PreferenceData.KEY_IS_DEEPLINK_USER,context,value);
}
public static boolean isDeeplinkUser(Context context){
// read boolean value from preference
// you can use this function for check, is user if from deeplink or not.
//true : Deeplink user
//false : Organic user
return PreferenceData.getBooleanPrefs(PreferenceData.KEY_IS_DEEPLINK_USER,context);
}
public static boolean getFireAD(final JSONObject deeplinkObj){
try {
if (deeplinkObj != null && deeplinkObj.has("firead") && deeplinkObj.get("firead").toString().equalsIgnoreCase("false")) {
return false;
}
return true;
}catch (Exception e){
return true;
}
}
b. In your SplashActivity class find or create the onStart method and add the following code to initialize the Mobibox SDK. Depending on whether you build your app for testing or for production, you must enable or disable logs when initializing Mobibox SDK by setting the second parameter to true or false.
@Override
protected void onStart() {
super.onStart();
// Branch init
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
@Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
Log.e("BRANCH SDK", referringParams.toString());
// latest
JSONObject sessionParams = Branch.getInstance().getLatestReferringParams();
Log.e("sessions params :",sessionParams.toString());
// first
JSONObject installParams = Branch.getInstance().getFirstReferringParams();
Log.e("install params :",installParams.toString());
processDeepLinkParams(sessionParams);
} else {
Log.e("BRANCH SDK", error.getMessage());
}
// Start your task from here
navigateSample();
}
}, this.getIntent().getData(), this);
}
@Override
public void onNewIntent(Intent intent) {
this.setIntent(intent);
}
public void processDeepLinkParams(JSONObject deeplinkObj){
try {
if (deeplinkObj.has("OpenPage") && deeplinkObj.get("OpenPage").toString().equals("BActivity")) {
Utility.setDeeplinkUser(this,true);
MA_PreferenceData.setStringPref(MA_PreferenceData.KEY_DEEPLINK_REFERRER,
this, deeplinkObj.toString().replace("\\",""));
String language = Locale.getDefault().toString();
final boolean fireAd = Utility.getFireAD(deeplinkObj);
Log.e("jprocessDeepLinkParams", "fireAd: "+fireAd);
MobiboxConfig config = new MobiboxConfig(this, false, language,fireAd);
}
}catch (JSONException e){
Log.e("json problem",e.toString());
}
}
private void navigateSample() {
Logcat.e(tag, "nav next called , shouldbilling="+Utility.isOpenBillingActivity(SplashSceenActivity.this));
if (Utility.isNetworkAvailable(SplashSceenActivity.this)) {
if (MA_Billing.getBillingStatus(SplashSceenActivity.this)) {
callLookupSample();
} else if(Utility.isDeeplinkUser(SplashSceenActivity.this)) {
Intent intent = new Intent(SplashSceenActivity.this, MA_BillingActivity.class);
startActivityForResult(intent, SDK_CODE);
}else{
gotoSample();
}
} else {
gotoSample();
}
}
private void callLookupSample() {
lookup = new MA_Lookup(SplashSceenActivity.this);
lookup.LookUpSubscriber(SplashSceenActivity.this);
}
private void gotoSample() {
Intent browserIntent = new Intent(SplashSceenActivity.this, HomeActivity.class);
startActivity(browserIntent);
finish();
}
Portal view setup (webview)
1. We recommend to create Main Activity class with Navigation drawer menu, where first menu should me “Home” which is for portal view fragment class and then other menu you can create as per your app requirements but at then end of the navigation menu you need to create one button called “Upgrade to premium ” which is only visible for deeplink user and on click you need open billing activity intent. like below screenshot:

Deeplink User
Organic User
2. You need to create a layout xml file (fragment_portal.xml) for portalview and add following code on it.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webview_portal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<LinearLayou
android:id="@+id/layout_error"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true"
android:layout_height="wrap_content">
<ImageView
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_gravity="center"
android:src="@drawable/logo"/>
<TextView
android:id="@+id/textview_message"
android:layout_width="250dp"
android:layout_marginTop="16dp"
android:textStyle="bold"
android:gravity="center"
android:textSize="22sp"
android:text="@string/no_internet_cnx_found"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
3. You need to create PortalViewFragement class and add following code into it.
import android.Manifest;
import android.app.Dialog;
import android.app.DownloadManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.support.v4.app.ActivityCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.DownloadListener;
import android.webkit.URLUtil;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.adjust.sdk.Adjust;
import com.sample.sdk_integration.utilities.Utility;
import com.ma.paymentsdk.objects.MA_Constants;
import com.ma.paymentsdk.objects.MA_Dialogs;
import com.ma.paymentsdk.utilities.Logcat;
import com.ma.paymentsdk.utilities.MA_Utility;
public class PortalViewFragment extends Fragment {
private View mView;
private Context mContext;
public static final String tag = "PortalViewFragment";
private WebView webView;
private Dialog dialog;
private boolean started = true;
private LinearLayout mLayoutError;
private TextView mTextViewMessage;
private final int REQUEST_WRITE_EXTERNAL_STORAGE = 9877;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_portal, container, false);
mContext = getActivity();
initWebView();
return mView;
}
public void initWebView() {
webView = (WebView) mView.findViewById(R.id.webview_portal);
mLayoutError = (LinearLayout)mView.findViewById(R.id.layout_error) ;
mTextViewMessage = (TextView)mView.findViewById(R.id.textview_message);
CookieManager.getInstance().setAcceptCookie(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setUseWideViewPort(true);
webView.getSettings().setLoadWithOverviewMode(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setPluginState(WebSettings.PluginState.ON);
webView.setWebChromeClient(new WebChromeClient());
if (MA_Utility.isOnline(mContext)) {
mLayoutError.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
webView.postUrl(MA_Constants.CONTENT_REDIRECTION_URL, MA_Dialogs.getRedirectionUrl(mContext));
webView.setWebViewClient(new WebViewController());
webView.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent,
String contentDisposition, String mimeTyp
long contentLength) {
if(ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimeType);
//------------------------COOKIE!!------------------------
String cookies = CookieManager.getInstance().getCookie(url);
request.addRequestHeader("cookie", cookies);
//------------------------COOKIE!!------------------------
request.addRequestHeader("User-Agent", userAgent);
request.setDescription("Downloading file...");
request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimeType));
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, contentDisposition, mimeType));
DownloadMnager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
dm.enqueue(request);
}else
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
}
});
} else {
mLayoutError.setVisibility(View.VISIBLE);
webView.setVisibility(View.GONE);
}
}
@Override
public void onResume() {
Adjust.onResume();
super.onResume();
webView.onResume();
}
@Override
public void onPause() {
super.onPause();
Adjust.onPause();
webView.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
webView.loadUrl("about:blank");
}
public class WebViewController extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (started) {
dialog = Utility.createDialog(mContext);
dialog.show();
started = false;
}
publicoid onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
if (!started) {
try {
Thread sthread = new Thread() {
@Override
public void run() {
try {
int waited = 0;
while (wited <= 300) {
sleep(100);
waited += 100;
}
} catch (InterruptedException e) {
} finally {
try {
getActivity().runOnUiThread(new Runnable() {
public void run() {
Utility.removeDialog(dialog);
}
});
} catch (Exception e) {
}
}
}
};
sthread.start();
} catch (Exception e) {
Utility.removeDialog(dialog);
Logcat.e(tag, e.getMessage())
}
}
}
}Billing setup
a. Use the below code, anywhere in your code to open Billing Activity for your user.
private final int SDK_CODE = 11;
Intent intent = new Intent(context, MA_BillingActivity.class);
startActivityForResult(intent, SDK_CODE);
b. In the same activity where you opened the billing activity, call onActivityResult to check if payment was successful or not.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SDK_CODE) {
if(resultCode == RESULT_OK){
if (MA_Billing.getBillingStatus(Context)) {
//User has successfully subscribed
} else {
//User did not subscribe
}
}
if (resultCode == RESULT_CANCELED) {
//User did not subscribe
}
}
}
Billing lookup
a. To check if user has subscribed (premium) or not through Mobibox SDK when using the app, you can check the below locale variable.
if (MA_Billing.getBillingStatus(Context)) {
//User has successfully subscribed
} else {
//User did not subscribe
}
If user is premium according to the locale variable above, you can check the real-time billing status on the backend of the subscribed user by calling the lookup function (lookup on MSISDN). The activity to call this function, should implement MA_OnLookUp
MA_Lookup lookup = new MA_Lookup();
lookup.LookUpSubscriber(Context);
b. The lookup result will give a clear idea about user’s status, which allow you to handle the permissions as you wish.
public void lookupResult(int status, String Description, Boolean isFreeTrial, String subscriptionDate, String expiryDate) {
Logcat.e(tag, "User status: " + status + " description: " + Description);
try {
//Status values:
//0 for active users - subscribed and billed users
//1 for none active users - subscribed users but not billed due to low balance
//2 for deleted users - unsubscribed users => Open billing Activity
//3 user not found => Open billing Activity
} catch (Exception e) {
//Exception occurred, manage the case as you wish
}
}
Billing Information
Mobibox SDK provides additional billing information such as: AccountDetails and how-to unsub from the app. These are only applicable if the user is premium.
a. showUnsubDialogFromAPI
MA_Dialogs.showUnsubDialogFromAPI(Context);
b. showMyAccountFromAPI
MA_Dialogs.showMyAccountFromAPI(Context);
Custom Events tracking
SendEvent Function can be called for tracking any event or action you want to track (events should be defined on Mobibox interface first). In the example below, we are tracking whenever user presses on upgrade button.
EventHandler.sendEvent(MA_Constants.UPGRADE_EVENT, tag, "", "", new EventTrackerListener() {
@Override
public void onSendEventComplete(JSONObject json) {
}
@Override
public void onSendEventError(String error) {
}
},context);
Force update app
“Force update app” is a very important feature handled by Mobibox SDK. From backend, you can set if you want to force update the app in a certain country (Maybe some new feature or new operator’s rule needs to be implemented, then only force update concerned country).
If the force Update value is true, then SDK will automatically ask user to update the app before using it and will redirect him to play store link.
Host app can integrate this feature, by checking if the app needed force update and user did not update, then don’t allow user to use the app and close it.
if(MA_Billing.isAppNeedsUpdate(context)) {
//Means app needs update but user did not update, then close app
finish();
}
Free version support
Some apps, may or may not, have support for free version (free features or free content). This property can be set from backend (by country) and SDK will store it locally.
This way, host app can know if there is a free version to be granted to user or not.
if (MA_Billing.getIsFreelink(context)){
//App has free version, so user can still use the service with limited access
} else {
//App does not have free version, and therefor user cannot use the app -> close the app by finishing the activity
}
MISDN auto-detection
Whenever possible, Mobibox SDK will auto detect MSISDN and make it available to host app.
String phoneNumber = MA_Utility.getPhoneNumber(MainActivity.this);
if (phoneNumber != null && !phoneNumber.isEmpty()){
//Phone number detected
} else {
//Phone number couldn't be detected
}
Sample project For better understanding of the integration of Mobibox SDK, please download the sample project from the link below:
https://bitbucket.org/BIG_Genius/sdk-integration-deeplink