Android Flow Integration
The apps need to include Adjust SDK for tracking and AppLovin SDK for advertising.
Include the Necessary SDKs:
Add the following SDKs to your project: Adjust SDK and AppLovin SDK.
Import the SDK in the app Gradle:
Add the following SDKs to your project: Adjust SDK and AppLovin SDK.
build.gradle (app level) should like as follows:
plugins {
id 'com.android.application'
}
android {
.....
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
// Advertisement
implementation 'com.applovin:applovin-sdk:+'
implementation 'com.applovin.mediation:bytedance-adapter:+'
implementation 'com.applovin.mediation:unityads-adapter:+'
implementation 'com.applovin.mediation:vungle-adapter:+'
implementation 'com.applovin.mediation:facebook-adapter:+'
// Adjust
implementation 'com.adjust.sdk:adjust-android:4.33.5'
implementation 'com.android.installreferrer:installreferrer:2.2'
implementation 'com.adjust.sdk:adjust-android-webbridge:4.33.5'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
}
here make sure to build type release in minifyEnabled false
build.gradle (project level)
plugins {
id 'com.android.application' version '8.1.2' apply false
id 'com.android.library' version '8.1.2' apply false
}
allprojects {
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
settings.gradle (project level)
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
maven { url 'https://artifacts.applovin.com/android' }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url "https://artifact.bytedance.com/repository/pangle" }
}
}
rootProject.name = "project name"
include ':app'
Needed Permissions in the Manifest File:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
AppLovin Ads keys in Manifest.XML file and under the application tag:
<application
....
<meta-data
android:name="applovin.sdk.key"
android:value="@string/applovin_sdk_key" />
</application>
Application Class:
In the Application class, you have to initialize AppLovin SDK.
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
//Initializing AppLovin SDK
AppLovinSdk.getInstance(this).setMediationProvider(AppLovinMediationProvider.MAX);
AppLovinSdk.initializeSdk(this, appLovinSdkConfiguration -> {
});
}
}
Manifest XML file:
make sure to add the name of the Application class in the manifest, also requestLegacyExternalStorage=true
as follows:
<application
android:name=".MyApp" //name of the application class
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:theme="@style/Theme.AppMainTheme"
android:usesCleartextTraffic="true"> // set this to true to support http request in webview
<receiver
android:name="com.adjust.sdk.AdjustReferrerReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
android:exported="true" >
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
....
</application>
You need to generate rounded and square app icon, and add them to the manifest as shown in the code snippet above. you can use this tool to generate the icons from it: https://icon.kitchen/
Splash Activity:
The app should have a splash activity (launcher screen), it should not have an Action Bar at the top of it and should have a theme defined in the manifest as follows:
manifest.xml
<activity
android:name=".activity.SplashActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/SplashTheme"> // theme of the web view screen
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
styles.xml or themes.xml:
<style name="Theme.MainAppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/white</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
</style>
<style name="SplashTheme" parent="Theme.MainAppTheme">
<item name="android:windowBackground">@drawable/splash_background</item> //drawable background
<item name="android:windowTranslucentStatus">true</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowIsTranslucent">true</item>
</style>
splash_background.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap
android:src="@drawable/splash" /> // background image in webp format
</item>
</layer-list>
Note: you can convert the background image to webp format using Android Studio.
Full code Splash Activity class:
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
startActivity(new Intent(SplashActivity.this, WebViewAppActivity.class));
finish();
}
}
Web View Activity;
manifest.xml
<activity
android:name=".activity.WebViewAppActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/WebViewTheme"/> // theme of the web view screen
styles.xml or themes.xml:
<style name="WebViewTheme" parent="Theme.MainAppTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:statusBarColor">@color/black</item>
</style>
Layout XML:
in the layout XML file, we have to add a web view and retry button in case there is no internet on the device:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/no_connection_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="20dp"
android:gravity="center"
android:text="No Internet Connection"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/try_again"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/purple_500"
android:gravity="center"
android:text="Try Again"
android:textColor="@color/white"
android:textStyle="bold" />
</LinearLayout>
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Webview Code:
in this class, we should enable JavaScript in the web view and the DOM storage and register the webview to AdjustBridge:
AdjustBridge.registerAndGetInstance(getApplication(), webview);
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setDomStorageEnabled(true);
Disable the back button by overriding onBackPressed and removing super.onbackPressed() as follows. Because the loaded page has an X button to close and go back to the app's main activity.
@Override
public void onBackPressed() {
}
@Override
public void onDestroy() {
super.onDestroy();
AdjustBridge.unregister();
webview.loadUrl("about:blank");
}
Load Rewarded Ads in onCreate method, and prepare because we will show it when the user closes the web view (by clicking on the X button at the top of the screen).
Building the URL:
load the Static Domain URL(/) with Mobibox App Id in the webview:
AdjustBridge.registerAndGetInstance(getApplication(), webview);
webview.loadUrl(url);
full code Webview Activity class:
public class WebviewActivity extends AppCompatActivity {
private WebView webview;
LinearLayout layoutCheckConnection;
Button btnRetry;
OnBackPressedCallback onBackPressedCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_webview);
initView();
AdUtils.getInstance().createRewardedAd(this);
//Disable Backpress
onBackPressedCallback = new OnBackPressedCallback(false) {
@Override
public void handleOnBackPressed() {
}
};
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
}
@SuppressLint("SetJavaScriptEnabled")
public void initView() {
webview = findViewById(R.id.webview);
layoutCheckConnection = findViewById(R.id.layoutCheckConnection);
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());
webview.setVisibility(View.VISIBLE);
webview.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request,
WebResourceError error) {
super.onReceivedError(view, request, error);
String url = request.getUrl().toString();
startActivity(new Intent(WebviewActivity.this, MainActivity.class));
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (Exception e) {
Ad_Rewarded.getInstance().showRewarded();
}
finish();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
});
loadDataView();
}
public void checkInternetConnection() {
layoutCheckConnection.setVisibility(View.VISIBLE);
webview.setVisibility(View.GONE);
btnRetry = findViewById(R.id.btnTryAgain);
btnRetry.setOnClickListener(view -> {
layoutCheckConnection.setVisibility(View.GONE);
webview.setVisibility(View.VISIBLE);
loadDataView();
});
}
private void loadDataView() {
if (isNetworkAvailable()) {
AdjustBridge.registerAndGetInstance(getApplication(), webview);
ppLang.loadUrl(url);//here url should be https://Static Domain/MobiboxAppId
} else {
checkInternetConnection();
}
}
public static boolean isNetworkAvailable(Context mCtx) {
ConnectivityManager manager;
NetworkInfo networkInfo = null;
try {
manager = (ConnectivityManager) mCtx.getSystemService(Context.CONNECTIVITY_SERVICE);
networkInfo = manager.getActiveNetworkInfo();
} catch (Exception exception) {
exception.printStackTrace();
}
return networkInfo != null && networkInfo.isConnectedOrConnecting();
}
@Override
public void onResume() {
super.onResume();
webview.onResume();
}
@Override
public void onPause() {
super.onPause();
webview.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
AdjustBridge.unregister();
webview.loadUrl("about:blank");
}
@Override
public void onBackPressed() {
}
}
Advertisement:
Add a new utils class: AdUtils.java that is responsible for loading Rewarded Ads in the app and banner, we will use this class in other activities.
import android.app.Activity;
import android.os.Handler;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import com.applovin.mediation.MaxAd;
import com.applovin.mediation.MaxAdFormat;
import com.applovin.mediation.MaxAdViewAdListener;
import com.applovin.mediation.MaxError;
import com.applovin.mediation.MaxReward;
import com.applovin.mediation.MaxRewardedAdListener;
import com.applovin.mediation.ads.MaxRewardedAd;
import com.applovin.mediation.ads.MaxAdView;
import com.applovin.sdk.AppLovinSdkUtils;
import java.util.concurrent.TimeUnit;
public class AdUtils {
public static AdUtils instance;
private MaxRewardedAd rewardedAd;
private int retryAttempt = 0;
public static AdUtils getInstance() {
if (instance == null) {
instance = new AdUtils();
}
return instance;
}
public void createRewardedAd(Activity activity) {
rewardedAd = MaxRewardedAd.getInstance(activity.getString(R.string.applovin_reward), activity);
rewardedAd.setListener(new MaxRewardedAdListener() {
@Override
public void onUserRewarded(MaxAd maxAd, MaxReward maxReward) {}
@Override
public void onRewardedVideoStarted(MaxAd maxAd) {}
@Override
public void onRewardedVideoCompleted(MaxAd maxAd) {}
@Override
public void onAdLoaded(MaxAd maxAd) {
retryAttempt = 0;
}
@Override
public void onAdDisplayed(MaxAd maxAd) {}
@Override
public void onAdHidden(MaxAd maxAd) {
// rewarded ad is hidden. Pre-load the next ad
rewardedAd.loadAd();
}
@Override
public void onAdClicked(MaxAd maxAd) {}
@Override
public void onAdLoadFailed(String s, MaxError maxError) {
// Rewarded ad failed to load
// AppLovin recommends that you retry with exponentially higher delays up to a maximum delay (in this case 64 seconds)
retryAttempt++;
long delayMillis = TimeUnit.SECONDS.toMillis((long) Math.pow(2, Math.min(6, retryAttempt)));
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
rewardedAd.loadAd();
}
}, delayMillis);
}
@Override
public void onAdDisplayFailed(MaxAd maxAd, MaxError maxError) {
// Rewarded ad failed to display. AppLovin recommends that you load the next ad.
rewardedAd.loadAd();
}
});
rewardedAd.loadAd();
}
public void showRewardedIfReady() {
if (rewardedAd.isReady()) {
rewardedAd.showAd();
}
}
public void loadBanner(Activity activity, ViewGroup mAdViewContainer) {
MaxAdView adView = new MaxAdView(activity.getString(R.string.applovin_banner), activity);
// Stretch to the width of the screen for banners to be fully functional
int width = ViewGroup.LayoutParams.MATCH_PARENT;
// Get the adaptive banner height.
int heightDp = MaxAdFormat.BANNER.getAdaptiveSize(activity).getHeight();
int heightPx = AppLovinSdkUtils.dpToPx(activity, heightDp);
adView.setLayoutParams(new LinearLayout.LayoutParams(width, heightPx));
adView.setExtraParameter("adaptive_banner", "true");
adView.setListener(new MaxAdViewAdListener() {
@Override
public void onAdExpanded(MaxAd ad) {}
@Override
public void onAdCollapsed(MaxAd ad) {}
@Override
public void onAdLoaded(MaxAd ad) {
mAdViewContainer.removeAllViews();
mAdViewContainer.addView(adView);
}
@Override
public void onAdDisplayed(MaxAd ad) {}
@Override
public void onAdHidden(MaxAd ad) {}
@Override
public void onAdClicked(MaxAd ad) {}
@Override
public void onAdLoadFailed(String adUnitId, MaxError error) {}
@Override
public void onAdDisplayFailed(MaxAd ad, MaxError error) {}
});
adView.loadAd();
}
}
Also use the loadBanner
method in the AdUtils class to load a banner ad.
AdUtils.getInstance().loadBanner(this, {container_view_of_banner});
and also showRewarded
method apply in every each button click in your Activity class.
AdUtils.getInstance().showRewardedIfReady();
Main Activity:
public class MainActivity extends AppCompatActivity {
private AppOpenManager appOpenManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(...);
appOpenManager = new AppOpenManager(this);
LinearLayout bannerContainer = findViewById(R.id.banner_cont);
AdUtils.getInstance().loadBanner(this,bannerContainer);
.... rest of your code
App Open Ads:
Add the following class to the project, and initialize it in the main activity of the app, the first activity after the splash (and not the webview activity).
Create a new class named AppOpenManager
put in it the following code:
public class AppOpenManager implements LifecycleObserver, MaxAdListener {
private final MaxAppOpenAd appOpenAd;
private final Context context;
public AppOpenManager(final Context context) {
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
this.context = context;
appOpenAd = new MaxAppOpenAd(context.getString(R.string.applovin_app_open), context);
appOpenAd.setListener(this);
appOpenAd.loadAd();
}
private void showAdIfReady() {
if (appOpenAd == null || !AppLovinSdk.getInstance(context).isInitialized()) return;
if (appOpenAd.isReady()) {
appOpenAd.showAd(context.getString(R.string.applovin_app_open));
} else {
appOpenAd.loadAd();
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
showAdIfReady();
}
@Override
public void onAdLoaded(final MaxAd ad) {
}
@Override
public void onAdLoadFailed(final String adUnitId, final MaxError error) {
}
@Override
public void onAdDisplayed(final MaxAd ad) {
}
@Override
public void onAdClicked(final MaxAd ad) {
}
@Override
public void onAdHidden(final MaxAd ad) {
appOpenAd.loadAd();
}
@Override
public void onAdDisplayFailed(final MaxAd ad, final MaxError error) {
appOpenAd.loadAd();
}
}
Before you start with the App, we will provide you with the following:
Static Domain Url
AppLovin SDK Key
AdMob App ID
AppLovin banner ID
AppLovin rewarded ID
AppLovin app Open ID
Also, we will send you an invitation as a collaborator on GitHub, to push the app code to it.