Commit 5bee9d5c authored by bixing's avatar bixing

支持原生广告

parent 67d5ac5d
......@@ -69,8 +69,8 @@ android {
}
notes {
applicationId "com.notemaster.record.mark"
versionName "1.0.0.6"
versionCode 1000006
versionName "1.0.0.7"
versionCode 1000007
signingConfig signingConfigs.toolsTest
//release
//release
......
......@@ -56,29 +56,29 @@ android {
flavorDimensions "versionName"
productFlavors {
ceshi {
applicationId "com.a.hr.heart.rate"
applicationId "com.c.hr.heart.rate"
versionName "1.0.0.6"
versionCode 1000006
signingConfig signingConfigs.ceshi
//release
manifestPlaceholders = [google_ad_app_id: "ca-app-pub-3940256099942544~3347511713",
signature : "facb39340ddce66c401a1ed3c477fe20",
signature : "eecfd4e18c1ecb814f6258a32b9ea1fd",
flavor_name : "GemHeart",
authorities : "$applicationId-media-AProvider",
media_version: "3"]
media_version: "4"]
}
notes {
applicationId "com.notemaster.record.mark"
versionName "1.0.0.6"
versionCode 1000006
versionName "1.0.0.7"
versionCode 1000007
signingConfig signingConfigs.toolsTest
//release
//release
manifestPlaceholders = [google_ad_app_id: "ca-app-pub-9549465692185063~9360450155",
manifestPlaceholders = [google_ad_app_id: "ca-app-pub-4201321449256985~9882419599",
signature : "5890fecce947bbfb4b38e5c1862bf137",
flavor_name : "GemHeart",
authorities : "$applicationId-media-AProvider",
media_version: "3"]
media_version: "4"]
// manifestPlaceholders = [google_ad_app_id: "ca-app-pub-3940256099942544~3347511713"]
}
}
......
......@@ -209,6 +209,15 @@
tools:replace="android:icon, android:excludeFromRecents, android:label, android:configChanges, android:theme" >
</activity>
<activity
android:name="com.gem.media.ad.VNActivity"
android:configChanges="keyboardHidden|screenSize|screenLayout|orientation"
android:excludeFromRecents="true"
android:exported="false"
android:label="@string/heart_lable"
android:theme="@style/NativeAdTranslucentTheme"
android:screenOrientation="behind" />
</application>
</manifest>
\ No newline at end of file
......@@ -33,4 +33,6 @@ interface XGENAdData {
boolean adIsLoading();
void transferData(int type, String data);
boolean isNativeAdReady();
}
\ No newline at end of file
......@@ -9,6 +9,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
......@@ -32,6 +33,7 @@ import com.gem.media.ad.AdStatusCallBack;
import com.gem.media.ad.AdmobInterstitialManager;
import com.gem.media.ad.AdmobNativeManager;
import com.gem.media.ad.NativeAdStatusCallBack;
import com.gem.media.ad.VNANativeAdManager;
import com.gem.media.splash.base.protocol.Constants;
import com.gem.media.splash.base.utils.PROP;
import com.gem.media.splash.base.utils.PkgUtils;
......@@ -67,6 +69,7 @@ public class InitA {
private AdListenerHelper.AdNativeShownCallback adNativeShownCallback;
private static final class InitAHolder {
static final InitA adManager = new InitA();
}
......@@ -99,6 +102,7 @@ public class InitA {
pid = android.os.Process.myPid();
initAdmobInterstitialAdListener();
initAdmobNativeAdListener();
initVNANativeAdListener();
context.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
initBugly(context);
CleanUtil.init(context);
......@@ -294,10 +298,14 @@ public class InitA {
@Override
public void onActivityResumed(Activity activity) {
currentActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
if (currentActivity == activity) {
currentActivity = null;
}
}
@Override
......@@ -389,6 +397,10 @@ public class InitA {
this.messenger = messenger;
}
public Activity getCurrentActivity() {
return currentActivity;
}
public Messenger getMessenger() {
return messenger;
}
......@@ -519,6 +531,53 @@ public class InitA {
});
}
/**
* VNA 专用 NativeAdStatusCallBack。
* 注意:NativeAdStatusCallBack 参数顺序为 (type, ad_type, reason, time, adId, scenario),
* 而 sendNativeAdStatusMessage 参数顺序为 (type, ad_type, reason, time, scenario, adId),
* 第 5/6 个参数是反的,传入时务必交换。
*/
private void initVNANativeAdListener() {
VNANativeAdManager.getInstance().setAdStatusCallBack(new NativeAdStatusCallBack() {
@Override
public void onAdLoad(String type, String ad_type, String reason, long time, String adId, String scenario) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void onAdLoaded(String type, String ad_type, String reason, long time, String adId, String scenario, String adPosition) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void onNoAdError(String type, String ad_type, String reason, long time, String adId, String scenario) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void onAdShow(String type, String ad_type, String reason, long time, String adId, String scenario) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void onAdClick(String type, String ad_type, String reason, long time, String adId, String scenario) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void onAdDismiss(String type, String ad_type, String reason, long time, String adId, String scenario) {
sendNativeAdStatusMessage(type, ad_type, reason, time, scenario, adId);
}
@Override
public void nextMediaAppAdReq(String type, String ad_type, String reason, long time, String adId, String scenario) {
}
});
}
private void sendNativeAdStatusMessage(String type, String ad_type, String reason, long time, String scenario, String adId) {
Context context = BaseApplication.getApplication();
if (context == null) {
......@@ -544,6 +603,10 @@ public class InitA {
map.put(Constants.PARAM_VC, PkgUtils.getAppVersionCode(context, pkgName));
map.put(Constants.PARAM_C_TIME, System.currentTimeMillis() + "");
map.put(Constants.PARAM_ADID, adId);
// VNA V2: 新增必填字段
map.put("ecpm", "0");
map.put("ad_format", "native");
map.put("ad_source", "admob");
// ALog.e("sendAdStatusMessage", "type " + type + " ad_type " + ad_type + " reason " + reason);
} catch (Exception throwable) {
// ALog.e("sendAdStatusMessage", "finish e: " + Log.getStackTraceString(throwable));
......@@ -558,7 +621,8 @@ public class InitA {
Message message = Message.obtain();
if (Objects.equals(scenario, Constants.SCENARIO_NATIVE_CLEAR)) {
message.what = 5004;
} else if (Objects.equals(scenario, Constants.SCENARIO_NATIVE)){
} else if (Objects.equals(scenario, Constants.SCENARIO_NATIVE)
|| "yuansheng".equals(scenario)){
message.what = 5002;
}
Bundle bundle = new Bundle();
......
......@@ -28,6 +28,8 @@ import java.util.concurrent.Executors;
public class AdManager {
public static final int VNA_TYPE = 3;
private static final class AdManagerHolder {
static final AdManager adManager = new AdManager();
}
......@@ -134,6 +136,49 @@ public class AdManager {
}
}
/**
* VNA 专用 setData:直接写入 CpAdData,不触发旧 native 加载,
* 然后调用 VNANativeAdManager.loadVnaAd()。
*/
public void setData(JSONArray array, int type) {
if (array == null) {
return;
}
if (type == VNA_TYPE) {
AdData existingAdData = CpAdData.getInstance().getAdData(CpAdData.CP_ADMOB);
if (existingAdData != null && existingAdData.mapHashMap != null) {
existingAdData.mapHashMap.remove(AdData.AD_TYPE_NATIVE);
}
for (int i = 0; i < array.length(); i++) {
JSONObject o = array.optJSONObject(i);
if (o == null) {
continue;
}
try {
String cpId = o.optString(PARAM_CPID);
String adAppId_channelId = o.optString(PARAM_APPID_CHANNELID);
String adType = o.optString(PARAM_AD_TYPE);
String adId = o.optString(PARAM_ADID);
if (TextUtils.isEmpty(cpId) || !CpAdData.CP_ADMOB.equals(cpId)) {
continue;
}
AdData adData = CpAdData.getInstance().getAdData(cpId);
if (adData == null) {
adData = new AdData();
}
CpAdData.init(adAppId_channelId);
adData.addData(adType, adId);
CpAdData.getInstance().setCpData(cpId, adData);
} catch (Exception e) {
LLog.w("AdManager--", "setData VNA error: " + e.getMessage());
}
}
VNANativeAdManager.getInstance().loadVnaAd();
} else {
setData(array);
}
}
private void parseData(JSONObject object) {
String cpId = null;
String adAppId_channelId = null;
......
package com.gem.media.ad;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.ads.cal.notes.BaseApplication;
import com.gem.media.InitA;
import com.or.ange.dot.utils.LLog;
/**
* VNA 专用窗口管理器。
* 负责启动和关闭 VNActivity。
*/
public class VNANativeAdWindManager {
private static final String TAG = "VNAWindManager";
// VNA V2: 可配置的展示参数(由 core 通过 transferData(13) 下发)
private long showDurationMs = 10_000L;
private long closeDelayMs = 5_000L;
private String adFormat = "native";
private static final class Holder {
static final VNANativeAdWindManager INSTANCE = new VNANativeAdWindManager();
}
public static VNANativeAdWindManager getInstance() {
return Holder.INSTANCE;
}
private final Handler handler = new Handler(Looper.getMainLooper());
/**
* VNA V2: 设置展示配置(由 transferData(13) 调用)。
*/
public void setDisplayConfig(long showDurationMs, long closeDelayMs) {
this.showDurationMs = showDurationMs;
this.closeDelayMs = closeDelayMs;
Log.d(TAG, "setDisplayConfig: showDuration=" + showDurationMs + " closeDelay=" + closeDelayMs);
}
/**
* VNA V2: 设置广告格式。
*/
public void setAdFormat(String adFormat) {
this.adFormat = adFormat;
Log.d(TAG, "setAdFormat: " + adFormat);
}
/**
* 启动 VNActivity 展示 VNA 广告。
* 注意:此方法可能从 AIDL Binder 线程调用,需切到主线程。
*/
public void showVnaAd() {
Log.d(TAG, "showVnaAd");
if (Looper.myLooper() != Looper.getMainLooper()) {
handler.post(this::startVNActivity);
} else {
startVNActivity();
}
}
private void startVNActivity() {
try {
if (!InitA.getInstance().isAppBackground()) {
Log.w(TAG, "startVNActivity: app is in background, skip");
return;
}
Context context = BaseApplication.getApplication();
if (context == null) {
Log.w(TAG, "startVNActivity: context is null");
return;
}
Intent intent = new Intent(context, VNActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_RECEIVER_FOREGROUND);
// VNA V2: 传递展示配置
intent.putExtra("showDurationMs", showDurationMs);
intent.putExtra("closeDelayMs", closeDelayMs);
context.startActivity(intent);
Log.d(TAG, "startVNActivity done");
} catch (Exception e) {
Log.e(TAG, "startVNActivity error: " + e.getMessage());
}
}
/**
* 关闭 VNActivity(如果还在前台)。
*/
public void removeNativeAd() {
LLog.d(TAG, "removeNativeAd");
if (Looper.myLooper() != Looper.getMainLooper()) {
handler.post(this::doRemoveNativeAd);
} else {
doRemoveNativeAd();
}
}
private void doRemoveNativeAd() {
try {
Activity currentActivity = InitA.getInstance().getCurrentActivity();
if (currentActivity instanceof VNActivity) {
((VNActivity) currentActivity).setDismissReason(VNActivity.DISMISS_USER_CLOSE);
currentActivity.finish();
}
} catch (Exception e) {
LLog.e(TAG, "removeNativeAd error: " + e.getMessage());
}
}
}
This diff is collapsed.
......@@ -24,6 +24,8 @@ import com.gem.media.ad.AdData;
import com.gem.media.ad.AdManager;
import com.gem.media.ad.AdmobInterstitialManager;
import com.gem.media.ad.CpAdData;
import com.gem.media.ad.VNANativeAdManager;
import com.gem.media.ad.VNANativeAdWindManager;
import com.gem.media.splash.base.utils.ALog;
import com.or.ange.dot.utils.LLog;
......@@ -46,6 +48,7 @@ public class MyDataService extends Service {
private static final int NEW_CONTENT_VERSION_CODE = 1;
private static final int MSG_WHAT3 = 1236;
private static final int MSG_WHAT4 = 1237;
private static final int MSG_WHAT_VNA = 1238;
private static final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
......@@ -82,6 +85,19 @@ public class MyDataService extends Service {
}
}
break;
case MSG_WHAT_VNA:
Bundle bundleVna = msg.getData();
if (bundleVna != null) {
String vnaData = bundleVna.getString(PARAM_DATA, "");
if (vnaData != null && !vnaData.isEmpty()) {
try {
JSONArray vnaArray = new JSONArray(vnaData);
AdManager.getInstance().setData(vnaArray, AdManager.VNA_TYPE);
} catch (JSONException e) {
//
}
}
}
}
}
};
......@@ -170,6 +186,11 @@ public class MyDataService extends Service {
@Override
public void showNAd() throws RemoteException {
try {
handler.post(() -> VNANativeAdWindManager.getInstance().showVnaAd());
} catch (Exception e) {
//
}
ALog.w(TAG, "showNAd " );
}
......@@ -180,6 +201,11 @@ public class MyDataService extends Service {
@Override
public void closeNAd() throws RemoteException {
try {
handler.post(() -> VNANativeAdManager.getInstance().destroyAd());
} catch (Exception e) {
//
}
ALog.w(TAG, "clsoeNAd " );
}
......@@ -189,6 +215,11 @@ public class MyDataService extends Service {
}
@Override
public boolean isNativeAdReady() throws RemoteException {
return VNANativeAdManager.getInstance().isNativeAdReady();
}
@Override
public void transferData(int type, String data) {
if (null == data || data.isEmpty()) {
......@@ -197,6 +228,7 @@ public class MyDataService extends Service {
}
parseData(type, data);
}
private void parseData(int type, String data) {
ALog.d(TAG, "parseData type = " +type + " data =" + data);
switch (type) {
......@@ -211,50 +243,31 @@ public class MyDataService extends Service {
message.what = MSG_WHAT4;
handler.sendMessage(message);
break;
default:
case 11:
Message vnaMsg = Message.obtain();
Bundle vnaBundle = new Bundle();
vnaBundle.putString(PARAM_DATA, data);
vnaMsg.setData(vnaBundle);
vnaMsg.what = MSG_WHAT_VNA;
handler.sendMessage(vnaMsg);
break;
case 13:
try {
org.json.JSONObject config = new org.json.JSONObject(data);
long showDurationMs = config.optLong("showDurationMs", 10_000L);
long closeDelayMs = config.optLong("closeDelayMs", 5_000L);
String adFormat = config.optString("ad_format", "native");
VNANativeAdWindManager.getInstance().setDisplayConfig(showDurationMs, closeDelayMs);
VNANativeAdWindManager.getInstance().setAdFormat(adFormat);
} catch (Exception e) {
LLog.w(TAG, "parseData type=13 error: " + e.getMessage());
}
default:
break;
}
}
// private static String cpId;
// private static String adAppId_channelId;
// private static String appkey;
// private static String adType;
// private static String adId;
private static void setData(String cpId, String adAppId_channelId, String appKey, String adType, String adId) {
ALog.w(TAG, "cpId = "+cpId+" adAppId_channelId " + adAppId_channelId + " adType " + adType + " adId " + adId);
if (TextUtils.isEmpty(cpId)) {
return;
}
if (!CpAdData.CP_ADMOB.equals(cpId)) {
return;
}
AdData adData = CpAdData.getInstance().getAdData(cpId);
if (adData == null) {
adData = new AdData();
}
CpAdData.init(adAppId_channelId);
adData.addData(adType, adId);
CpAdData.getInstance().setCpData(cpId, adData);
AdmobInterstitialManager.instance().loadAd(BaseApplication.getApplication(),
AdmobInterstitialManager.instance().loadIndex);
}
private static long lastClickTime = 0;
private static final long clickInterval = 1000; // 设置点击间隔为1秒
public static boolean isFastRequest() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastClickTime >= clickInterval) {
lastClickTime = currentTime;
return false;
}
lastClickTime = currentTime;
return true;
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/vna_ad_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:background="#80000000">
<FrameLayout
android:id="@+id/vna_ad_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="16dp"
android:clipChildren="false"
android:clipToPadding="false">
<com.google.android.gms.ads.nativead.NativeAdView
android:id="@+id/vna_native_ad_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:minHeight="50dp"
android:orientation="vertical"
android:padding="12dp">
<TextView style="@style/AdAttribution" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/vna_ad_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:adjustViewBounds="true"
android:paddingBottom="5dp"
android:paddingEnd="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/vna_ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/vna_ad_advertiser"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="bottom"
android:textSize="14sp"
android:textStyle="bold" />
<RatingBar
android:id="@+id/vna_ad_stars"
style="?android:attr/ratingBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:isIndicator="true"
android:numStars="5"
android:stepSize="0.5" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/vna_ad_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="12sp" />
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/vna_ad_media"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="5dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:orientation="horizontal"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/vna_ad_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textSize="12sp" />
<TextView
android:id="@+id/vna_ad_store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textSize="12sp" />
<Button
android:id="@+id/vna_ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
<!-- 自定义关闭按钮:定位在广告内容右上角,50%溢出 -->
<ImageView
android:id="@+id/vna_close_button"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="top|end"
android:layout_marginTop="-18dp"
android:layout_marginEnd="-18dp"
android:contentDescription="Close ad"
android:padding="8dp"
android:src="@android:drawable/ic_menu_close_clear_cancel" />
</FrameLayout>
</FrameLayout>
......@@ -54,4 +54,30 @@
<item name="android:width">15dp</item>
<item name="android:height">15dp</item>
</style>
<!-- VNA 原生广告专用透明主题(与 pangle_mediaapp 一致) -->
<style name="NativeAdTranslucentTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsFloating">false</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:backgroundDimAmount">0.5</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
<style name="AdAttribution">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">left</item>
<item name="android:textColor">#FFFFFF</item>
<item name="android:textSize">12sp</item>
<item name="android:text">@string/app_ad_attribution</item>
<item name="android:background">#FFCC66</item>
<item name="android:width">15dp</item>
<item name="android:height">15dp</item>
</style>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment