├── Demo ├── build.gradle ├── gradle.properties ├── libs │ └── android-query-full.0.26.7.jar ├── proguard-project.txt ├── settings.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── qq │ │ └── e │ │ └── union │ │ ├── adapter │ │ └── test │ │ │ ├── activity │ │ │ └── MediationTestActivity.java │ │ │ ├── model │ │ │ ├── LayerConfig.java │ │ │ └── NetworkConfig.java │ │ │ └── util │ │ │ └── ConfigReader.java │ │ └── demo │ │ ├── BaseActivity.java │ │ ├── Constants.java │ │ ├── DemoApplication.java │ │ ├── DemoBiddingC2SUtils.java │ │ ├── DemoGameTestActivity.java │ │ ├── DemoListActivity.java │ │ ├── DemoUtil.java │ │ ├── HybridADActivity.java │ │ ├── InnerDemoApplication.java │ │ ├── NativeADUnifiedActivity.java │ │ ├── NativeADUnifiedAdInfoView.java │ │ ├── NativeADUnifiedFullScreenActivity.java │ │ ├── NativeADUnifiedFullScreenFeedActivity.java │ │ ├── NativeADUnifiedListViewActivity.java │ │ ├── NativeADUnifiedPreMovieActivity.java │ │ ├── NativeADUnifiedRecyclerViewActivity.java │ │ ├── NativeADUnifiedSampleActivity.java │ │ ├── NativeExpressADActivity.java │ │ ├── NativeExpressDemoActivity.java │ │ ├── NativeExpressImmersiveActivity.java │ │ ├── NativeExpressRecyclerViewActivity.java │ │ ├── PositionId.java │ │ ├── RewardVideoActivity.java │ │ ├── SDKVersionActivity.java │ │ ├── SplashADActivity.java │ │ ├── SplashActivity.java │ │ ├── UnifiedBannerActivity.java │ │ ├── UnifiedInterstitialADActivity.java │ │ ├── UnifiedInterstitialFullScreenADActivity.java │ │ ├── adapter │ │ └── PosIdArrayAdapter.java │ │ ├── util │ │ ├── DemoRequestUtils.java │ │ ├── DownloadApkConfirmDialog.java │ │ ├── DownloadApkConfirmDialogWebView.java │ │ ├── DownloadConfirmHelper.java │ │ ├── MainHandler.java │ │ ├── PxUtils.java │ │ ├── ScreenUtils.java │ │ ├── SplashZoomOutLayout.java │ │ ├── SplashZoomOutManager.java │ │ └── ToastUtil.java │ │ └── view │ │ ├── FullScreenVideoView.java │ │ └── ViewUtils.java │ └── res │ ├── anim │ ├── download_confirm_dialog_slide_right_in.xml │ └── download_confirm_dialog_slide_up.xml │ ├── drawable-sw600dp │ └── gdt_splash_text.png │ ├── drawable-xxhdpi │ ├── delete.png │ ├── icon_download_gray.png │ ├── icon_link.png │ └── icon_to_link.png │ ├── drawable │ ├── background_bottom_immersive_content.xml │ ├── background_button.xml │ ├── background_circle.xml │ ├── background_circle_blue.xml │ ├── download_confirm_background_confirm.xml │ ├── download_confirm_background_landscape.xml │ ├── download_confirm_background_portrait.xml │ ├── gdt_ic_express_close.png │ ├── gdt_icon.png │ ├── gdt_logo.png │ ├── gdt_logo_white.png │ ├── gdt_splash_holder.png │ ├── gdt_splash_text.png │ ├── ic_download_confirm_close.xml │ ├── ic_keyboard_arrow_down_black_24dp.xml │ ├── shape_bg_call_to_action.xml │ └── shape_bg_countdown.xml │ ├── layout │ ├── activity_demo_game.xml │ ├── activity_hybrid.xml │ ├── activity_mediation_test.xml │ ├── activity_native_express_ad.xml │ ├── activity_native_express_demo.xml │ ├── activity_native_express_recycler_view.xml │ ├── activity_native_unified_ad.xml │ ├── activity_native_unified_ad_custom_video.xml │ ├── activity_native_unified_ad_full_screen.xml │ ├── activity_native_unified_ad_listview.xml │ ├── activity_native_unified_ad_premovie.xml │ ├── activity_native_unified_ad_recyclerview.xml │ ├── activity_native_unified_ad_simple.xml │ ├── activity_reward_video.xml │ ├── activity_sdk_version.xml │ ├── activity_splash.xml │ ├── activity_splash_ad.xml │ ├── activity_unified_banner.xml │ ├── activity_unified_interstitial_ad.xml │ ├── activity_unified_interstitial_fullscreen_video_ad.xml │ ├── contentlistitem.xml │ ├── dialog_custom_params.xml │ ├── dialog_id_collect.xml │ ├── download_confirm_dialog.xml │ ├── item_ad.xml │ ├── item_ad_unified.xml │ ├── item_ad_unified_full_screen_feed.xml │ ├── item_custom_params.xml │ ├── item_data.xml │ ├── item_express_ad.xml │ ├── item_full_screen_video_feed.xml │ ├── item_immersive_express_ad.xml │ ├── item_layer.xml │ ├── item_network.xml │ └── layout_native_unified_ad_info.xml │ ├── menu │ ├── banner.xml │ ├── interstitial_ad.xml │ ├── main.xml │ └── splash.xml │ ├── raw │ ├── p1.png │ ├── p2.png │ ├── p3.png │ ├── p4.png │ ├── p5.png │ ├── v1.mp4 │ ├── v2.mp4 │ ├── v3.mp4 │ ├── v4.mp4 │ └── v5.mp4 │ ├── values-sw600dp │ └── dimens.xml │ ├── values-sw800dp │ └── dimens.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values │ ├── arrays.xml │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ ├── strings_pref.xml │ └── styles.xml │ └── xml │ └── network_security_config.xml ├── GDTSDK.unionNormal.4.640.1510.aar └── README.md /Demo/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | mavenCentral() 5 | google() 6 | } 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:${project.GRADLE_VERSION}" 9 | } 10 | } 11 | 12 | repositories { 13 | jcenter() 14 | mavenCentral() 15 | google() 16 | flatDir { 17 | dirs 'libs' 18 | } 19 | } 20 | 21 | apply plugin: 'com.android.application' 22 | 23 | android { 24 | compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) 25 | buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION 26 | namespace 'com.qq.e.union.demo' 27 | defaultConfig { 28 | applicationId 'com.qq.e.union.demo' 29 | minSdkVersion 21 30 | targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) 31 | versionCode 1 32 | versionName '1.0' 33 | multiDexEnabled true 34 | buildConfigField "Class", "demolist", "DemoListActivity.class" 35 | buildConfigField "com.qq.e.union.demo.util.DemoRequestUtils", "DemoRequestUtils", "new com.qq.e.union.demo.util.DemoRequestUtils()" 36 | } 37 | 38 | buildTypes { 39 | debug { 40 | minifyEnabled false 41 | } 42 | release { 43 | minifyEnabled true 44 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' 45 | } 46 | } 47 | 48 | compileOptions { 49 | sourceCompatibility JavaVersion.VERSION_1_8 50 | targetCompatibility JavaVersion.VERSION_1_8 51 | } 52 | 53 | lintOptions { 54 | abortOnError false 55 | } 56 | 57 | packagingOptions { 58 | exclude 'androidsupportmultidexversion.txt' 59 | } 60 | } 61 | 62 | dependencies { 63 | implementation fileTree('libs/android-query-full.0.26.7.jar') 64 | implementation fileTree(dir: 'libs', include: ['*.aar']) 65 | implementation 'com.qq.e.union:union:4.640.1510' 66 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 67 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 68 | implementation "com.google.android.material:material:1.0.0" 69 | implementation 'androidx.cardview:cardview:1.0.0' 70 | implementation 'androidx.appcompat:appcompat:1.0.0' 71 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 72 | implementation 'com.tencent.bugly:crashreport:latest.release' 73 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1' 74 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1' 75 | implementation 'androidx.multidex:multidex:2.0.0' 76 | implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+' 77 | implementation fileTree(dir: 'aars', include: ['*.aar']) 78 | // 广告助手,接入详见:https://doc.weixin.qq.com/doc/w3_AI8ARgaEACc6NnpZ1i0T4ey9BsUuD?scode=AJEAIQdfAAoPvOyDr2AI8ARgaEACc 79 | implementation 'com.qq.e.union:tools:+' 80 | } -------------------------------------------------------------------------------- /Demo/gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. More details, visit 11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 12 | # org.gradle.parallel=true 13 | #Wed Jul 27 14:51:16 CST 2022 14 | android.useAndroidX=true 15 | android.enableJetifier=true 16 | org.gradle.jvmargs=-Xmx6g 17 | 18 | # 聚合Adapter版本号 19 | ADAPTER_VERSION=1 20 | 21 | # 第三方adn版本号 22 | admob_version=21.0.0 23 | applovin_version=11.4.4 24 | facebook_version=6.11.0 25 | ironsource_version=7.2.5 26 | mintegral_version=16.2.61 27 | pangle_version=4.7.0.6 28 | unity_version=4.4.1 29 | vungle_version=6.11.0 30 | 31 | GRADLE_VERSION=8.3.0 32 | 33 | # Minimum supported android sdk version 34 | ANDROID_BUILD_MIN_SDK_VERSION=14 35 | 36 | # Android build target sdk version 37 | ANDROID_BUILD_TARGET_SDK_VERSION=35 38 | 39 | # Android build tools version 40 | ANDROID_BUILD_TOOLS_VERSION=34.0.0 41 | 42 | # Android compile sdk version 43 | ANDROID_BUILD_SDK_VERSION=34 44 | 45 | #解决"Build包含自定义BuildConfig字段"错误 46 | android.defaults.buildfeatures.buildconfig=true 47 | #解决switch里面非 final 资源 ID 相关的报错 48 | android.nonFinalResIds=false 49 | -------------------------------------------------------------------------------- /Demo/libs/android-query-full.0.26.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/libs/android-query-full.0.26.7.jar -------------------------------------------------------------------------------- /Demo/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | 22 | # Demo工程里用到了AQuery库,因此需要添加下面的配置 23 | # 请开发者根据自己实际情况给第三方库的添加相应的混淆设置 24 | -dontwarn com.androidquery.** 25 | -keep class com.androidquery.** { *;} 26 | 27 | -dontwarn tv.danmaku.** 28 | -keep class tv.danmaku.** { *;} 29 | 30 | -dontwarn androidx.** 31 | 32 | # 如果使用了tbs版本的sdk需要进行以下配置 33 | -keep class com.tencent.smtt.** { *; } 34 | -dontwarn dalvik.** 35 | -dontwarn com.tencent.smtt.** 36 | 37 | # 如果使用了微信OpenSDK,需要添加如下配置 38 | -keep class com.tencent.mm.opensdk.** { 39 | *; 40 | } 41 | 42 | -keep class com.tencent.wxop.** { 43 | *; 44 | } 45 | 46 | -keep class com.tencent.mm.sdk.** { 47 | *; 48 | } 49 | 50 | # 如果接入了Bugly,需要添加如下配置 51 | -dontwarn com.tencent.bugly.** 52 | -keep public class com.tencent.bugly.**{*;} 53 | 54 | # Google IMA 55 | -keep class com.google.obf.** { *; } 56 | -keep interface com.google.obf.** { *; } 57 | 58 | -keep class com.google.ads.interactivemedia.** { *; } 59 | -keep interface com.google.ads.interactivemedia.** { *; } 60 | -dontwarn com.google.ads.interactivemedia.** 61 | 62 | # 如果接入了穿山甲,需要添加如下配置 63 | -keepclassmembers class * { 64 | *** getContext(...); 65 | *** getActivity(...); 66 | *** getResources(...); 67 | *** startActivity(...); 68 | *** startActivityForResult(...); 69 | *** registerReceiver(...); 70 | *** unregisterReceiver(...); 71 | *** query(...); 72 | *** getType(...); 73 | *** insert(...); 74 | *** delete(...); 75 | *** update(...); 76 | *** call(...); 77 | *** setResult(...); 78 | *** startService(...); 79 | *** stopService(...); 80 | *** bindService(...); 81 | *** unbindService(...); 82 | *** requestPermissions(...); 83 | *** getIdentifier(...); 84 | } 85 | -keep class com.bytedance.pangle.** {*;} 86 | -keep class com.bytedance.sdk.openadsdk.** { *; } 87 | -keep class com.bytedance.frameworks.** { *; } 88 | -keep class ms.bd.c.Pgl.**{*;} 89 | -keep class com.bytedance.mobsec.metasec.ml.**{*;} 90 | -keep class com.ss.android.**{*;} 91 | -keep class com.bytedance.embedapplog.** {*;} 92 | -keep class com.bytedance.embed_dr.** {*;} 93 | -keep class com.bykv.vk.** {*;} 94 | -keep class com.lynx.** { *; } 95 | -keep class android.support.v4.app.FragmentActivity{} 96 | -keep class androidx.fragment.app.FragmentActivity{} 97 | 98 | # 如果接入了百度联盟,需要添加如下配置 99 | -dontwarn com.baidu.mobads.sdk.api.** 100 | -keepclassmembers class * extends android.app.Activity { 101 | public void *(android.view.View); 102 | } 103 | -keepclassmembers enum * { 104 | public static **[] values(); 105 | public static ** valueOf(java.lang.String); 106 | } 107 | -keep class com.baidu.mobads.** { *; } 108 | -keep class com.style.widget.** {*;} 109 | -keep class com.component.** {*;} 110 | -keep class com.baidu.ad.magic.flute.** {*;} 111 | -keep class com.baidu.mobstat.forbes.** {*;} 112 | #9.22版本新增加混淆 113 | -keep class android.support.v7.widget.RecyclerView {*;} 114 | -keepnames class android.support.v7.widget.RecyclerView$* { 115 | public ; 116 | public ; 117 | } 118 | -keep class android.support.v7.widget.LinearLayoutManager {*;} 119 | -keep class android.support.v7.widget.PagerSnapHelper {*;} 120 | -keep class android.support.v4.view.ViewCompat {*;} 121 | -keep class android.support.v4.util.LongSparseArray {*;} 122 | -keep class android.support.v4.util.ArraySet {*;} 123 | -keep class android.support.v4.view.accessibility.AccessibilityNodeInfoCompat {*;} 124 | 125 | # 如果接入了快手联盟,需要添加如下配置 126 | -keep class org.chromium.** {*;} 127 | -keep class org.chromium.** { *; } 128 | -keep class aegon.chrome.** { *; } 129 | -keep class com.kwai.**{ *; } 130 | -dontwarn com.kwai.** 131 | -dontwarn com.kwad.** 132 | -dontwarn com.ksad.** 133 | -dontwarn aegon.chrome.** 134 | 135 | # qapm 平台 136 | -keep class com.tencent.qapmsdk.**{*;} 137 | -dontwarn com.tencent.qapmsdk.** 138 | -dontnote com.tencent.qapmsdk.** 139 | 140 | # 海外版本 pangle 增加混淆配置 141 | -keep class com.bytedance.sdk.** { *; } 142 | 143 | -ignorewarnings 144 | # 保留包名 145 | -keeppackagenames *.** -------------------------------------------------------------------------------- /Demo/settings.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/settings.gradle -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/adapter/test/activity/MediationTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.adapter.test.activity; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.os.Message; 7 | import androidx.annotation.IntDef; 8 | import androidx.annotation.NonNull; 9 | import androidx.annotation.Nullable; 10 | import androidx.appcompat.app.AppCompatActivity; 11 | import androidx.recyclerview.widget.DividerItemDecoration; 12 | import androidx.recyclerview.widget.LinearLayoutManager; 13 | import androidx.recyclerview.widget.RecyclerView; 14 | import android.text.TextUtils; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.ViewGroup; 18 | import android.widget.ImageView; 19 | import android.widget.TextView; 20 | 21 | import com.qq.e.union.demo.R; 22 | import com.qq.e.union.adapter.test.model.LayerConfig; 23 | import com.qq.e.union.adapter.test.model.NetworkConfig; 24 | import com.qq.e.union.adapter.test.util.ConfigReader; 25 | 26 | import org.json.JSONArray; 27 | import org.json.JSONException; 28 | import org.json.JSONObject; 29 | 30 | import java.lang.annotation.Retention; 31 | import java.lang.annotation.RetentionPolicy; 32 | import java.util.ArrayList; 33 | import java.util.List; 34 | 35 | public class MediationTestActivity extends AppCompatActivity { 36 | 37 | private RecyclerView mConfigsView; 38 | private ImageView mLoadingIcon; 39 | 40 | private Handler mHandler = new H(Looper.myLooper()); 41 | 42 | private List mConfigs = new ArrayList<>(); 43 | 44 | private static final int MSG_REFRESH_UI = 1; 45 | private static final int TYPE_LAYER = 1; 46 | private static final int TYPE_NETWORK = 2; 47 | 48 | @Retention(RetentionPolicy.SOURCE) 49 | @IntDef({TYPE_LAYER, TYPE_NETWORK}) 50 | @interface ViewType { 51 | } 52 | 53 | @Override 54 | protected void onCreate(@Nullable Bundle savedInstanceState) { 55 | super.onCreate(savedInstanceState); 56 | setContentView(R.layout.activity_mediation_test); 57 | mConfigsView = findViewById(R.id.configs_view); 58 | mLoadingIcon = findViewById(R.id.loading_icon); 59 | initDataAsync(); 60 | } 61 | 62 | @Override 63 | protected void onDestroy() { 64 | super.onDestroy(); 65 | mHandler.removeCallbacksAndMessages(null); 66 | } 67 | 68 | public void initDataAsync() { 69 | new Thread(new Runnable() { 70 | @Override 71 | public void run() { 72 | getLocalConfigs(); 73 | mHandler.sendEmptyMessage(MSG_REFRESH_UI); 74 | } 75 | }).start(); 76 | } 77 | 78 | private void getLocalConfigs() { 79 | String originalData = ConfigReader.getConfig(this); 80 | if (TextUtils.isEmpty(originalData)) { 81 | return; 82 | } 83 | try { 84 | JSONObject originalJson = new JSONObject(originalData); 85 | JSONArray layerConfigs = originalJson.optJSONArray("layerConfigs"); 86 | if (layerConfigs == null) { 87 | return; 88 | } 89 | for (int i = 0; i < layerConfigs.length(); i++) { 90 | JSONObject layer = layerConfigs.getJSONObject(i); 91 | mConfigs.add(new LayerConfig(layer)); 92 | } 93 | } catch (JSONException e) { 94 | e.printStackTrace(); 95 | } 96 | } 97 | 98 | private class H extends Handler { 99 | 100 | H(Looper looper) { 101 | super(looper); 102 | } 103 | 104 | @Override 105 | public void handleMessage(Message msg) { 106 | super.handleMessage(msg); 107 | if (msg.what == MSG_REFRESH_UI) { 108 | mLoadingIcon.setVisibility(View.GONE); 109 | mConfigsView.setLayoutManager(new LinearLayoutManager(MediationTestActivity.this)); 110 | mConfigsView.setAdapter(new ConfigsAdapter(mConfigs)); 111 | mConfigsView.addItemDecoration(new DividerItemDecoration(MediationTestActivity.this, DividerItemDecoration.VERTICAL)); 112 | } 113 | } 114 | } 115 | 116 | private class ConfigsAdapter extends RecyclerView.Adapter { 117 | 118 | private List mLayerConfigs; 119 | private List mSortConfigs = new ArrayList<>(); 120 | 121 | public ConfigsAdapter(List configs) { 122 | mLayerConfigs = configs; 123 | for (LayerConfig config : mLayerConfigs) { 124 | mSortConfigs.add(config); 125 | List networkConfigs = config.getNetworkConfigs(); 126 | if (networkConfigs != null && networkConfigs.size() > 0) { 127 | for (NetworkConfig networkConfig : networkConfigs) { 128 | mSortConfigs.add(networkConfig); 129 | } 130 | } 131 | } 132 | } 133 | 134 | @NonNull 135 | @Override 136 | public VH onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { 137 | View view = null; 138 | if (i == TYPE_NETWORK) { 139 | view = LayoutInflater.from(MediationTestActivity.this).inflate(R.layout.item_network, null); 140 | } else if (i == TYPE_LAYER) { 141 | view = LayoutInflater.from(MediationTestActivity.this).inflate(R.layout.item_layer, null); 142 | } 143 | return new VH(view, i); 144 | } 145 | 146 | @Override 147 | public void onBindViewHolder(@NonNull VH vh, int i) { 148 | @ViewType int viewType = getItemViewType(i); 149 | if (viewType == TYPE_LAYER) { 150 | vh.mLayer.setText(((LayerConfig) (mSortConfigs.get(i))).getPosId()); 151 | } else if (viewType == TYPE_NETWORK) { 152 | NetworkConfig networkConfig = (NetworkConfig) mSortConfigs.get(i); 153 | vh.mName.setText("渠道 : " + networkConfig.getName()); 154 | vh.mPosId.setText("PosId : " + networkConfig.getIdentity()); 155 | vh.mClassName.setText("渠道适配器 : " + networkConfig.getClassName()); 156 | vh.mExt.setText("其他信息 : " + networkConfig.getExt()); 157 | vh.mAdapterStatus.setText("适配器状态 : " + networkConfig.getAdapterStatus()); 158 | } 159 | } 160 | 161 | @Override 162 | public int getItemCount() { 163 | return mSortConfigs.size(); 164 | } 165 | 166 | @Override 167 | public @ViewType int getItemViewType(int i) { 168 | Object config = mSortConfigs.get(i); 169 | @ViewType int type = TYPE_LAYER; 170 | if (config instanceof NetworkConfig) { 171 | type = TYPE_NETWORK; 172 | } 173 | return type; 174 | } 175 | } 176 | 177 | private class VH extends RecyclerView.ViewHolder { 178 | 179 | public TextView mLayer; 180 | public TextView mName; 181 | public TextView mPosId; 182 | public TextView mExt; 183 | public TextView mClassName; 184 | public TextView mAdapterStatus; 185 | 186 | public VH(@NonNull View itemView, @ViewType int viewType) { 187 | super(itemView); 188 | switch (viewType) { 189 | case TYPE_LAYER: 190 | mLayer = itemView.findViewById(R.id.layer_title); 191 | break; 192 | case TYPE_NETWORK: 193 | mName = itemView.findViewById(R.id.network_name); 194 | mPosId = itemView.findViewById(R.id.network_posid); 195 | mExt = itemView.findViewById(R.id.network_ext); 196 | mClassName = itemView.findViewById(R.id.network_class_name); 197 | mAdapterStatus = itemView.findViewById(R.id.network_adapter_status); 198 | break; 199 | } 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/adapter/test/model/LayerConfig.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.adapter.test.model; 2 | 3 | import org.json.JSONArray; 4 | import org.json.JSONObject; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * name : SELF_SELLING // 三方渠道名称 11 | * posId : 1041 // 三方渠道posId 12 | */ 13 | public class LayerConfig { 14 | private String posId; 15 | private List networkConfigs; 16 | 17 | public LayerConfig(JSONObject layerConfig) { 18 | posId = layerConfig.optString("phyPosId"); 19 | networkConfigs = new ArrayList<>(); 20 | JSONArray array = layerConfig.optJSONArray("network"); 21 | if (array != null && array.length() >= 0) { 22 | for (int i = 0; i < array.length(); i++) { 23 | JSONObject config = array.optJSONObject(i); 24 | networkConfigs.add(new NetworkConfig(config)); 25 | } 26 | } 27 | } 28 | 29 | public String getPosId() { 30 | return posId; 31 | } 32 | 33 | public List getNetworkConfigs() { 34 | return networkConfigs; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/adapter/test/model/NetworkConfig.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.adapter.test.model; 2 | 3 | import android.text.TextUtils; 4 | 5 | import org.json.JSONObject; 6 | 7 | public class NetworkConfig { 8 | /** 9 | * name : SELF_SELLING // 三方渠道名称 10 | * posId : 1041 // 三方渠道posId 11 | * class_name : class_name_placeholder //类名 12 | * ext : {"x1": "a param"} // App 运营配置额外信息 13 | */ 14 | 15 | private String name; 16 | private String identity; 17 | private String className; 18 | private String ext; 19 | private String adapterStatus; 20 | 21 | public NetworkConfig(JSONObject config) { 22 | name = config.optString("name"); 23 | identity = config.optString("posId"); 24 | className = config.optString("className"); 25 | ext = config.optString("ext"); 26 | adapterStatus = "不可用"; 27 | if ("adshonor".equals(name) || "TSSP".equals(name) || "GDT".equals(name)) { 28 | adapterStatus = "内部渠道,忽略"; 29 | } else if (!TextUtils.isEmpty(className)) { 30 | try { 31 | Class.forName(className); 32 | adapterStatus = "正常"; 33 | } catch (ClassNotFoundException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | } 38 | 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | public String getIdentity() { 44 | return identity; 45 | } 46 | 47 | public String getClassName() { 48 | return className; 49 | } 50 | 51 | public String getExt() { 52 | return ext; 53 | } 54 | 55 | public String getAdapterStatus() { 56 | return adapterStatus; 57 | } 58 | } -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/adapter/test/util/ConfigReader.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.adapter.test.util; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import java.io.BufferedReader; 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.io.IOException; 10 | import java.io.InputStreamReader; 11 | 12 | public class ConfigReader { 13 | private static final String TAG = ConfigReader.class.getSimpleName(); 14 | 15 | public static String getConfig(Context context) { 16 | File dir = context.getDir("e_qq_com_mediation", Context.MODE_PRIVATE); 17 | if (!dir.exists()) { 18 | Log.e(TAG, "getConfig: e_qq_com_mediation is not directory"); 19 | return null; 20 | } 21 | File configFile = new File(dir, "test"); 22 | if (!configFile.exists()) { 23 | Log.e(TAG, "getConfig: file test is null"); 24 | return null; 25 | } 26 | 27 | BufferedReader br = null; 28 | try { 29 | InputStreamReader reader = new InputStreamReader(new FileInputStream(configFile), "UTF-8"); 30 | br = new BufferedReader(reader); 31 | String line = null; 32 | StringBuilder sb = new StringBuilder(); 33 | while ((line = (br.readLine())) != null) { 34 | sb.append(line); 35 | } 36 | return sb.toString(); 37 | } catch (IOException e) { 38 | e.printStackTrace(); 39 | } finally { 40 | if (br != null) { 41 | try { 42 | br.close(); 43 | } catch (Exception e1) { 44 | Log.e(TAG, "getConfig: Exception while close bufferreader"); 45 | } 46 | } 47 | } 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 4 | import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 5 | 6 | import android.content.Context; 7 | import android.content.pm.ActivityInfo; 8 | import android.content.res.Configuration; 9 | import android.os.Bundle; 10 | import android.view.View; 11 | import android.view.WindowManager; 12 | 13 | import androidx.fragment.app.FragmentActivity; 14 | 15 | public class BaseActivity extends FragmentActivity { 16 | 17 | public static final String AUTO_LOAD_AND_SHOW = "autoLoadAndShow"; 18 | 19 | protected boolean mIsLoadSuccess; 20 | protected boolean mIsLoadAndShow; 21 | protected String mBackupPosId; 22 | protected String mS2sBiddingToken; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | if(getIntent().getBooleanExtra(AUTO_LOAD_AND_SHOW, false)){ 28 | mIsLoadAndShow = true; 29 | mBackupPosId = getIntent().getStringExtra(Constants.POS_ID); 30 | 31 | WindowManager wm = 32 | ((WindowManager) this.getApplicationContext().getSystemService(Context.WINDOW_SERVICE)); 33 | if (getIntent().getIntExtra("orientation", 1) != DemoUtil.getOrientation(wm.getDefaultDisplay().getRotation())) { 34 | setRequestedOrientation(getIntent().getIntExtra("orientation", 1)); 35 | } else { 36 | loadAd(); 37 | } 38 | } 39 | 40 | } 41 | 42 | protected void loadAd() { 43 | } 44 | 45 | public void requestS2SBiddingToken(View view) { 46 | BuildConfig.DemoRequestUtils.requestBiddingToken(getPosId(), token -> mS2sBiddingToken = token); 47 | } 48 | 49 | protected String getPosId(){ 50 | return ""; 51 | } 52 | 53 | @Override 54 | public void onConfigurationChanged(Configuration newConfig) { 55 | super.onConfigurationChanged(newConfig); 56 | if (mIsLoadAndShow) { 57 | loadAd(); 58 | } 59 | } 60 | 61 | protected void changeScreenOrientation() { 62 | int currentOrientation = getResources().getConfiguration().orientation; 63 | if (currentOrientation == ORIENTATION_PORTRAIT) { 64 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 65 | } else if (currentOrientation == ORIENTATION_LANDSCAPE) { 66 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/Constants.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | public class Constants { 4 | public static final String BuglyAppID = "28d030a2bf"; 5 | public static String APPID = "1101152570"; 6 | public static final String POS_ID = "pos_id"; 7 | public static final String TOKEN = "token"; 8 | public static final String MIN_VIDEO_DURATION = "minVideoDuration"; 9 | public static final String MAX_VIDEO_DURATION = "maxVideoDuration"; 10 | public static final String PLAY_MUTE = "mute"; 11 | public static final String PLAY_NETWORK = "network"; 12 | public static final String NEED_COVER = "need_cover"; 13 | public static final String NEED_PROGRESS = "need_progress"; 14 | public static final String ENABLE_USER_CONTROL = "enable_user_control"; 15 | //按钮绑定给customview,点击后直接下载或进入落地页,与视频区域点击逻辑分开 16 | public static final String BUTTON_BIND_TO_CUSTOM_VIEW = "button_bind_to_custom_view"; 17 | public static final String NONE_OPTION = "none_option"; 18 | public static final String LOAD_AD_COUNT = "load_ad_count"; 19 | public static final String ITEMS_PER_AD = "items_per_ad"; 20 | public static final int VIDEO_DURATION_SETTING_MIN = 5; 21 | public static final int VIDEO_DURATION_SETTING_MAX = 60; 22 | } 23 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | public class DemoApplication extends InnerDemoApplication { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/DemoBiddingC2SUtils.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import com.qq.e.comm.constants.BiddingLossReason; 4 | import com.qq.e.comm.pi.IBidding; 5 | import com.qq.e.comm.pi.IBiddingLoss; 6 | 7 | import java.util.HashMap; 8 | 9 | public class DemoBiddingC2SUtils { 10 | 11 | private static int reportBiddingWinLoss = -1; 12 | 13 | public static final int REPORT_BIDDING_DISABLE = -1; 14 | public static final int REPORT_BIDDING_WIN = 0; 15 | public static final int REPORT_BIDDING_LOSS_LOW_PRICE = BiddingLossReason.LOW_PRICE; // 有广告回包,竞败 16 | public static final int REPORT_BIDDING_LOSS_NO_AD = BiddingLossReason.NO_AD; // 无广告回包 17 | public static final int REPORT_BIDDING_LOSS_NOT_COMPETITION = BiddingLossReason.NOT_COMPETITION; // 有广告回包但未参竞价 18 | public static final int REPORT_BIDDING_LOSS_OTHER = BiddingLossReason.OTHER; // 其他 19 | 20 | public static void setReportBiddingWinLoss(int reportBiddingWinLoss) { 21 | DemoBiddingC2SUtils.reportBiddingWinLoss = reportBiddingWinLoss; 22 | } 23 | 24 | public static void reportBiddingWinLoss(IBidding ad) { 25 | switch (reportBiddingWinLoss) { 26 | case REPORT_BIDDING_WIN: 27 | HashMap hashMap = new HashMap<>(); 28 | hashMap.put(IBidding.EXPECT_COST_PRICE, 200); 29 | hashMap.put(IBidding.HIGHEST_LOSS_PRICE, 199); 30 | ad.sendWinNotification(hashMap); 31 | break; 32 | case REPORT_BIDDING_LOSS_LOW_PRICE: 33 | case REPORT_BIDDING_LOSS_NO_AD: 34 | case REPORT_BIDDING_LOSS_NOT_COMPETITION: 35 | case REPORT_BIDDING_LOSS_OTHER: { 36 | HashMap hashMapLoss = new HashMap<>(); 37 | hashMapLoss.put(IBidding.WIN_PRICE, 300); 38 | hashMapLoss.put(IBidding.LOSS_REASON, reportBiddingWinLoss); 39 | hashMapLoss.put(IBidding.ADN_ID, "WinAdnID"); 40 | ad.sendLossNotification(hashMapLoss); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | public static void reportBiddingNoAd(IBiddingLoss ad) { 47 | HashMap hashMap = new HashMap<>(); 48 | hashMap.put(IBidding.WIN_PRICE, 300); 49 | hashMap.put(IBidding.LOSS_REASON, BiddingLossReason.NO_AD); 50 | hashMap.put(IBidding.ADN_ID, "WinAdnID"); 51 | ad.sendLossNotification(hashMap); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/DemoGameTestActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.content.pm.ActivityInfo; 4 | import android.os.Bundle; 5 | import android.text.Editable; 6 | import android.util.Log; 7 | import android.util.Patterns; 8 | import android.view.View; 9 | import android.widget.CheckBox; 10 | import android.widget.EditText; 11 | 12 | import com.qq.e.ads.rewardvideo.RewardVideoAD; 13 | import com.qq.e.ads.rewardvideo.RewardVideoADListener; 14 | import com.qq.e.comm.managers.GDTAdSdk; 15 | import com.qq.e.comm.util.AdError; 16 | import com.qq.e.union.demo.util.ToastUtil; 17 | 18 | import java.util.Locale; 19 | import java.util.Map; 20 | 21 | import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 22 | import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 23 | 24 | /** 25 | * 试玩广告测试Demo 26 | * 输入试玩广告地址,在正常激励视频广告中展示。 27 | */ 28 | public class DemoGameTestActivity extends BaseActivity implements RewardVideoADListener { 29 | 30 | private static final String TAG = DemoGameTestActivity.class.getSimpleName(); 31 | private static final String POS_ID = "6040295592058680"; 32 | private RewardVideoAD rewardVideoAD; 33 | private EditText demoGameUrlEdt; 34 | private boolean showing; 35 | private String demoGameUrlDefault = "https://developers.adnet.qq.com/open/tryable?debug=unsdk"; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | setContentView(R.layout.activity_demo_game); 41 | demoGameUrlEdt = findViewById(R.id.demo_game_url); 42 | demoGameUrlEdt.setText(demoGameUrlDefault); 43 | } 44 | 45 | public void onClick(View view) { 46 | switch (view.getId()) { 47 | case R.id.change_orientation_button: 48 | int currentOrientation = getResources().getConfiguration().orientation; 49 | if (currentOrientation == ORIENTATION_PORTRAIT) { 50 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 51 | } else if (currentOrientation == ORIENTATION_LANDSCAPE) { 52 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 53 | } 54 | break; 55 | case R.id.show_ad_button: 56 | if (checkDemoGameUrl()) { 57 | if (showing) { 58 | return; 59 | } 60 | boolean volumeOn = ((CheckBox) findViewById(R.id.volume_on_checkbox)).isChecked(); 61 | rewardVideoAD = new RewardVideoAD(this, POS_ID, this, volumeOn); 62 | rewardVideoAD.loadAD(); 63 | } 64 | break; 65 | } 66 | } 67 | 68 | private boolean checkDemoGameUrl() { 69 | Editable urlEditable = demoGameUrlEdt.getText(); 70 | if (urlEditable == null || urlEditable.length() == 0) { 71 | ToastUtil.s("请输入试玩广告地址"); 72 | return false; 73 | } else if (!Patterns.WEB_URL.matcher(urlEditable).matches()) { 74 | ToastUtil.l("请输入有效的试玩广告地址"); 75 | return false; 76 | } 77 | GDTAdSdk.getGDTAdManger().getDevTools().testDemoGame(DemoGameTestActivity.this, urlEditable.toString()); 78 | return true; 79 | } 80 | 81 | /** 82 | * 广告加载成功,可在此回调后进行广告展示 83 | **/ 84 | @Override 85 | public void onADLoad() { 86 | Log.i(TAG, "onADLoad"); 87 | } 88 | 89 | /** 90 | * 视频素材缓存成功,可在此回调后进行广告展示 91 | */ 92 | @Override 93 | public void onVideoCached() { 94 | Log.i(TAG, "onVideoCached"); 95 | } 96 | 97 | /** 98 | * 激励视频广告页面展示 99 | */ 100 | @Override 101 | public void onADShow() { 102 | showing = true; 103 | Log.i(TAG, "onADShow"); 104 | } 105 | 106 | /** 107 | * 激励视频广告曝光 108 | */ 109 | @Override 110 | public void onADExpose() { 111 | Log.i(TAG, "onADExpose"); 112 | } 113 | 114 | /** 115 | * 激励视频触发激励(观看视频大于一定时长或者视频播放完毕) 116 | */ 117 | @Override 118 | public void onReward(Map map) { 119 | Log.i(TAG, "onReward"); 120 | } 121 | 122 | /** 123 | * 激励视频广告被点击 124 | */ 125 | @Override 126 | public void onADClick() { 127 | Log.i(TAG, "onADClick"); 128 | } 129 | 130 | /** 131 | * 激励视频播放完毕 132 | */ 133 | @Override 134 | public void onVideoComplete() { 135 | Log.i(TAG, "onVideoComplete"); 136 | } 137 | 138 | /** 139 | * 激励视频广告被关闭 140 | */ 141 | @Override 142 | public void onADClose() { 143 | showing = false; 144 | Log.i(TAG, "onADClose"); 145 | } 146 | 147 | /** 148 | * 广告流程出错 149 | */ 150 | @Override 151 | public void onError(AdError adError) { 152 | showing = false; 153 | String msg = String.format(Locale.getDefault(), "onError, error code: %d, error msg: %s", 154 | adError.getErrorCode(), adError.getErrorMsg()); 155 | ToastUtil.l(msg); 156 | Log.i(TAG, "onError, adError=" + msg); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/DemoUtil.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import androidx.annotation.NonNull; 6 | import android.view.View; 7 | import android.view.inputmethod.InputMethodManager; 8 | 9 | import com.androidquery.callback.BitmapAjaxCallback; 10 | import com.qq.e.comm.constants.LoadAdParams; 11 | import com.qq.e.comm.managers.status.SDKStatus; 12 | import com.qq.e.union.demo.util.ToastUtil; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | 18 | /** 19 | * Created by hechao on 2018/2/8. 20 | */ 21 | 22 | public class DemoUtil { 23 | 24 | private static boolean sNeedSetBidECPM = false; 25 | 26 | public static final void hideSoftInput(Activity activity) { 27 | InputMethodManager imm = 28 | (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); 29 | View focusView = activity.getCurrentFocus(); 30 | if (focusView != null) { 31 | imm.hideSoftInputFromWindow(focusView.getWindowToken(), 0); //强制隐藏键盘 32 | } 33 | } 34 | 35 | public static void setAQueryImageUserAgent(){ 36 | BitmapAjaxCallback.setAgent("GDTMobSDK-AQuery-"+ SDKStatus.getIntegrationSDKVersion()); 37 | } 38 | 39 | public static void setNeedSetBidECPM(boolean need) { 40 | sNeedSetBidECPM = need; 41 | } 42 | 43 | public static boolean isNeedSetBidECPM() { 44 | return sNeedSetBidECPM; 45 | } 46 | 47 | @NonNull 48 | public static LoadAdParams getLoadAdParams(String value) { 49 | Map info = new HashMap<>(); 50 | info.put("custom_key", value); 51 | info.put("staIn", "com.qq.e.demo"); 52 | info.put("thrmei", "aaaa_bbbb_cccc_dddd"); 53 | LoadAdParams loadAdParams = new LoadAdParams(); 54 | loadAdParams.setDevExtra(info); 55 | return loadAdParams; 56 | } 57 | 58 | public static boolean isAdValid(boolean loadSuccess, boolean isValid, boolean showAd) { 59 | if (!loadSuccess) { 60 | ToastUtil.l("请加载广告成功后再进行校验 ! "); 61 | } else { 62 | if (!showAd || !isValid) { 63 | ToastUtil.l("广告" + (isValid ? "有效" : "无效")); 64 | } 65 | } 66 | return isValid; 67 | } 68 | 69 | public static int getOrientation(int orientation) { 70 | switch (orientation) { 71 | case 0: 72 | case 2: 73 | return 1; 74 | case 1: 75 | case 3: 76 | return 0; 77 | } 78 | return 1; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/HybridADActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.os.Bundle; 4 | import androidx.annotation.Nullable; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.CheckBox; 9 | import android.widget.EditText; 10 | 11 | import com.qq.e.ads.hybrid.HybridAD; 12 | import com.qq.e.ads.hybrid.HybridADListener; 13 | import com.qq.e.ads.hybrid.HybridADSetting; 14 | import com.qq.e.comm.util.AdError; 15 | import com.qq.e.union.demo.util.ToastUtil; 16 | 17 | import java.util.Locale; 18 | 19 | /** 20 | * Created by chaotao on 2018/12/24 . 21 | **/ 22 | public class HybridADActivity extends BaseActivity implements View.OnClickListener, HybridADListener { 23 | 24 | private static final String TAG = HybridADActivity.class.getSimpleName(); 25 | 26 | @Override 27 | protected void onCreate(@Nullable Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_hybrid); 30 | findViewById(R.id.go).setOnClickListener(this); 31 | } 32 | 33 | @Override 34 | public void onClick(View v) { 35 | switch (v.getId()) { 36 | case R.id.go: 37 | String url = ((EditText) findViewById(R.id.url)).getText().toString(); 38 | if (!TextUtils.isEmpty(url)) { 39 | HybridADSetting setting = fillHybridADSetting(); 40 | if (setting != null) { 41 | HybridAD hybridAD = new HybridAD(this, setting, this); 42 | hybridAD.loadUrl(url); 43 | } 44 | } 45 | break; 46 | } 47 | } 48 | 49 | private HybridADSetting fillHybridADSetting() { 50 | HybridADSetting setting = new HybridADSetting().type(HybridADSetting.TYPE_REWARD_VIDEO); 51 | if (((CheckBox) findViewById(R.id.cb_titleBarHeight)).isChecked()) { 52 | String s = ((EditText) findViewById(R.id.et_titleBarHeight)).getText().toString(); 53 | try { 54 | setting.titleBarHeight(Integer.valueOf(s)); 55 | } catch (NumberFormatException e) { 56 | ToastUtil.l("导航栏高度输入不合法"); 57 | return null; 58 | } 59 | } 60 | if (((CheckBox) findViewById(R.id.cb_titleBarColor)).isChecked()) { 61 | String s = ((EditText) findViewById(R.id.et_titleBarColor)).getText().toString(); 62 | try { 63 | setting.titleBarColor(Long.valueOf(s, 16).intValue()); 64 | } catch (NumberFormatException e) { 65 | ToastUtil.l("导航栏颜色输入不合法"); 66 | return null; 67 | } 68 | } 69 | if (((CheckBox) findViewById(R.id.cb_title)).isChecked()) { 70 | String s = ((EditText) findViewById(R.id.et_title)).getText().toString(); 71 | if (!TextUtils.isEmpty(s)) { 72 | setting.title(s); 73 | } else { 74 | ToastUtil.l("导航栏title输入为空"); 75 | return null; 76 | } 77 | } 78 | if (((CheckBox) findViewById(R.id.cb_titleColor)).isChecked()) { 79 | String s = ((EditText) findViewById(R.id.et_titleColor)).getText().toString(); 80 | try { 81 | setting.titleColor(Long.valueOf(s, 16).intValue()); 82 | } catch (NumberFormatException e) { 83 | ToastUtil.l("导航栏title字体颜色输入不合法"); 84 | return null; 85 | } 86 | } 87 | if (((CheckBox) findViewById(R.id.cb_titleSize)).isChecked()) { 88 | String s = ((EditText) findViewById(R.id.et_titleSize)).getText().toString(); 89 | try { 90 | setting.titleSize(Integer.valueOf(s)); 91 | } catch (NumberFormatException e) { 92 | ToastUtil.l("导航栏title字体大小输入不合法"); 93 | return null; 94 | } 95 | } 96 | if (((CheckBox) findViewById(R.id.cb_back)).isChecked()) { 97 | String s = ((EditText) findViewById(R.id.et_back)).getText().toString(); 98 | if (!TextUtils.isEmpty(s)) { 99 | setting.backButtonImage(s); 100 | } else { 101 | ToastUtil.l("导航栏back键icon资源名输入为空"); 102 | return null; 103 | } 104 | } 105 | if (((CheckBox) findViewById(R.id.cb_close)).isChecked()) { 106 | String s = ((EditText) findViewById(R.id.et_close)).getText().toString(); 107 | if (!TextUtils.isEmpty(s)) { 108 | setting.closeButtonImage(s); 109 | } else { 110 | ToastUtil.l("导航栏close键icon资源名输入为空"); 111 | return null; 112 | } 113 | } 114 | if (((CheckBox) findViewById(R.id.cb_seperator)).isChecked()) { 115 | String s = ((EditText) findViewById(R.id.et_seperator)).getText().toString(); 116 | try { 117 | setting.separatorColor(Long.valueOf(s, 16).intValue()); 118 | } catch (NumberFormatException e) { 119 | ToastUtil.l("分割线色值输入不合法"); 120 | return null; 121 | } 122 | } 123 | if (((CheckBox) findViewById(R.id.cb_back_seperator)).isChecked()) { 124 | String s = ((EditText) findViewById(R.id.et_back_seperator)).getText().toString(); 125 | try { 126 | setting.backSeparatorLength(Integer.valueOf(s)); 127 | } catch (NumberFormatException e) { 128 | ToastUtil.l("back键分割线高度输入不合法"); 129 | return null; 130 | } 131 | } 132 | return setting; 133 | } 134 | 135 | @Override 136 | public void onPageShow() { 137 | Log.i(TAG, "onPageShow"); 138 | } 139 | 140 | @Override 141 | public void onLoadFinished() { 142 | Log.i(TAG, "onLoadFinished"); 143 | } 144 | 145 | @Override 146 | public void onClose() { 147 | Log.i(TAG, "onClose"); 148 | } 149 | 150 | @Override 151 | public void onError(AdError error) { 152 | String msg = String.format(Locale.getDefault(), "onError, error code: %d, error msg: %s", 153 | error.getErrorCode(), error.getErrorMsg()); 154 | ToastUtil.l(msg); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/InnerDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.pm.ActivityInfo; 6 | import android.content.pm.PackageInfo; 7 | import android.content.pm.PackageManager; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.webkit.WebView; 12 | 13 | import com.qq.e.comm.managers.GDTAdSdk; 14 | import com.qq.e.comm.managers.setting.GlobalSetting; 15 | import com.tencent.bugly.crashreport.CrashReport; 16 | 17 | import androidx.multidex.MultiDexApplication; 18 | 19 | public class InnerDemoApplication extends MultiDexApplication { 20 | 21 | protected static Application appContext; 22 | 23 | @Override 24 | public void onCreate() { 25 | super.onCreate(); 26 | appContext = this; 27 | initializeApp(); 28 | } 29 | 30 | private void initializeApp() { 31 | configureDemo(); 32 | configureWebView(); 33 | configureGDTAdSDK(); 34 | startGDTAdSDK(); 35 | registerActivities(); 36 | } 37 | 38 | private void configureDemo() { 39 | DemoUtil.setAQueryImageUserAgent(); 40 | CrashReport.initCrashReport(this, Constants.BuglyAppID, true); 41 | } 42 | 43 | private void configureWebView() { 44 | // 如果 App 是多进程,建议设置 WebView.setDataDirectorySuffix 避免 WebView 多进程崩溃 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 46 | String processName = Application.getProcessName(); 47 | String packageName = this.getPackageName(); 48 | if (!packageName.equals(processName)) { 49 | WebView.setDataDirectorySuffix(processName); 50 | } 51 | } 52 | } 53 | 54 | protected void configureGDTAdSDK() { 55 | // 建议在初始化 SDK 前进行此设置 56 | GlobalSetting.setChannel(1); 57 | GlobalSetting.setEnableMediationTool(true); 58 | GlobalSetting.setEnableCollectAppInstallStatus(true); 59 | } 60 | 61 | private void startGDTAdSDK() { 62 | // 开发者请注意,4.560.1430 版本后 GDTAdSdk.init 接口已废弃,请尽快迁移至 GDTAdSdk.initWithoutStart、GDTAdSdk.start 63 | // 调用 initWithoutStart 接口进行初始化,该接口不会采集用户信息 64 | GDTAdSdk.initWithoutStart(this, Constants.APPID); 65 | // 调用 initWithoutStart 后请尽快调用 start,否则可能影响广告填充,造成收入下降 66 | GDTAdSdk.start(new GDTAdSdk.OnStartListener() { 67 | @Override 68 | public void onStartSuccess() { 69 | // 推荐开发者在 onStartSuccess 回调后开始拉广告 70 | } 71 | 72 | @Override 73 | public void onStartFailed(Exception e) { 74 | Log.e("gdt onStartFailed:", e.toString()); 75 | } 76 | }); 77 | } 78 | 79 | private void registerActivities() { 80 | try { 81 | String packageName = this.getPackageName(); 82 | //Get all activity classes in the AndroidManifest.xml 83 | PackageInfo packageInfo = this.getPackageManager().getPackageInfo( 84 | packageName, PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); 85 | if (packageInfo.activities != null) { 86 | for (ActivityInfo activity : packageInfo.activities) { 87 | Bundle metaData = activity.metaData; 88 | if (metaData != null && metaData.containsKey("id") 89 | && metaData.containsKey("content") && metaData.containsKey("action")) { 90 | Log.e("gdt", activity.name); 91 | try { 92 | Class.forName(activity.name); 93 | } catch (ClassNotFoundException e) { 94 | continue; 95 | } 96 | String id = metaData.getString("id"); 97 | String content = metaData.getString("content"); 98 | String action = metaData.getString("action"); 99 | registerActivity(action, id, content); 100 | } 101 | } 102 | } 103 | } catch (PackageManager.NameNotFoundException e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | 108 | protected void registerActivity(String action, String id, String content) { 109 | DemoListActivity.register(action, id, content); 110 | } 111 | 112 | public static Context getAppContext() { 113 | return appContext; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/NativeADUnifiedActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.AdapterView; 9 | import android.widget.CheckBox; 10 | import android.widget.CompoundButton; 11 | import android.widget.EditText; 12 | import android.widget.Spinner; 13 | 14 | import com.qq.e.union.demo.adapter.PosIdArrayAdapter; 15 | import com.qq.e.union.demo.util.ToastUtil; 16 | 17 | import static com.qq.e.union.demo.Constants.VIDEO_DURATION_SETTING_MAX; 18 | import static com.qq.e.union.demo.Constants.VIDEO_DURATION_SETTING_MIN; 19 | 20 | 21 | public class NativeADUnifiedActivity extends BaseActivity implements AdapterView.OnItemSelectedListener { 22 | 23 | private Spinner mPlayNetworkSpinner; 24 | private CheckBox mVideoOptionCheckBox; 25 | 26 | private CheckBox mMuteCheckBox; 27 | private CheckBox mCoverCheckBox; 28 | private CheckBox mProgressCheckBox; 29 | private CheckBox mControlCheckBox; 30 | private CheckBox mBindToCustomViewCheckBox; 31 | 32 | private static final String TAG = NativeADUnifiedActivity.class.getSimpleName(); 33 | 34 | private boolean mNoneOption = false; 35 | 36 | private EditText posIdEdt; 37 | 38 | private Spinner spinner; 39 | private PosIdArrayAdapter arrayAdapter; 40 | 41 | @Override 42 | public void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_native_unified_ad); 45 | 46 | posIdEdt = findViewById(R.id.posId); 47 | 48 | spinner = findViewById(R.id.id_spinner); 49 | arrayAdapter = new PosIdArrayAdapter(this, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.native_ad_unified_ad)); 50 | arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 51 | spinner.setAdapter(arrayAdapter); 52 | spinner.setOnItemSelectedListener(this); 53 | 54 | mVideoOptionCheckBox = findViewById(R.id.cb_none_video_option); 55 | mVideoOptionCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 56 | @Override 57 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 58 | Log.d(TAG, "onCheckedChanged: isChecked:" + isChecked); 59 | mNoneOption = isChecked; 60 | boolean enable = !isChecked; 61 | mPlayNetworkSpinner.setEnabled(enable); 62 | mMuteCheckBox.setEnabled(enable); 63 | mCoverCheckBox.setEnabled(enable); 64 | mProgressCheckBox.setEnabled(enable); 65 | mControlCheckBox.setEnabled(enable); 66 | } 67 | }); 68 | 69 | mPlayNetworkSpinner = findViewById(R.id.spinner_network); 70 | mPlayNetworkSpinner.setSelection(1); // 默认任何网络下都自动播放 71 | 72 | mMuteCheckBox = findViewById(R.id.btn_mute); 73 | mCoverCheckBox = findViewById(R.id.btn_cover); 74 | mProgressCheckBox = findViewById(R.id.btn_progress); 75 | mControlCheckBox = findViewById(R.id.btn_control); 76 | mBindToCustomViewCheckBox = findViewById(R.id.btn_bind_to_custom_view); 77 | } 78 | 79 | 80 | protected String getPosId() { 81 | String posId = ((EditText) findViewById(R.id.posId)).getText().toString(); 82 | return TextUtils.isEmpty(posId) ? PositionId.NATIVE_UNIFIED_POS_ID : posId; 83 | } 84 | 85 | private int getMinVideoDuration() { 86 | if (((CheckBox) findViewById(R.id.cbMinVideoDuration)).isChecked()) { 87 | try { 88 | int rst = 89 | Integer.parseInt(((EditText) findViewById(R.id.etMinVideoDuration)).getText().toString()); 90 | if (rst > 0) { 91 | return rst; 92 | } else { 93 | ToastUtil.l("最小视频时长输入须大于0!"); 94 | } 95 | } catch (NumberFormatException e) { 96 | ToastUtil.l("最小视频时长输入不是整数!"); 97 | } 98 | } 99 | return 0; 100 | } 101 | 102 | private int getMaxVideoDuration() { 103 | if (((CheckBox) findViewById(R.id.cbMaxVideoDuration)).isChecked()) { 104 | try { 105 | int rst = Integer.parseInt(((EditText) findViewById(R.id.etMaxVideoDuration)).getText() 106 | .toString()); 107 | if (rst >= VIDEO_DURATION_SETTING_MIN && rst <= VIDEO_DURATION_SETTING_MAX) { 108 | return rst; 109 | } else { 110 | ToastUtil.l("最大视频时长输入不在有效区间内!"); 111 | } 112 | } catch (NumberFormatException e) { 113 | ToastUtil.l("最大视频时长输入不是整数!"); 114 | } 115 | } 116 | return 0; 117 | } 118 | 119 | public void onNormalViewClicked(View view) { 120 | startActivity(getIntent(NativeADUnifiedSampleActivity.class)); 121 | } 122 | 123 | public void onRecyclerViewClicked(View view) { 124 | startActivity(getIntent(NativeADUnifiedRecyclerViewActivity.class)); 125 | } 126 | 127 | public void onListViewClick(View view) { 128 | startActivity(getIntent(NativeADUnifiedListViewActivity.class)); 129 | } 130 | 131 | public void onPreMovieClick(View view){ 132 | startActivity(getIntent(NativeADUnifiedPreMovieActivity.class)); 133 | } 134 | 135 | public void onFullScreenClick(View view) { 136 | startActivity(getIntent(NativeADUnifiedFullScreenActivity.class)); 137 | } 138 | 139 | public void onFullScreenFeedClick(View view){ 140 | startActivity(getIntent(NativeADUnifiedFullScreenFeedActivity.class)); 141 | } 142 | 143 | 144 | protected Intent getIntent(Class cls){ 145 | Intent intent = new Intent(); 146 | intent.setClass(this, cls); 147 | intent.putExtra(Constants.POS_ID, getPosId()); 148 | Log.d(TAG, "getIntent: BiddingToken: " + mS2sBiddingToken); 149 | intent.putExtra(Constants.TOKEN, mS2sBiddingToken); 150 | intent.putExtra(Constants.MIN_VIDEO_DURATION, getMinVideoDuration()); 151 | intent.putExtra(Constants.MAX_VIDEO_DURATION, getMaxVideoDuration()); 152 | intent.putExtra(Constants.NONE_OPTION, mNoneOption); 153 | intent.putExtra(Constants.PLAY_NETWORK, mPlayNetworkSpinner.getSelectedItemPosition()); 154 | intent.putExtra(Constants.PLAY_MUTE, mMuteCheckBox.isChecked()); 155 | intent.putExtra(Constants.NEED_COVER, mCoverCheckBox.isChecked()); 156 | intent.putExtra(Constants.NEED_PROGRESS, mProgressCheckBox.isChecked()); 157 | intent.putExtra(Constants.ENABLE_USER_CONTROL, mControlCheckBox.isChecked()); 158 | intent.putExtra(Constants.BUTTON_BIND_TO_CUSTOM_VIEW, mBindToCustomViewCheckBox.isChecked()); 159 | return intent; 160 | } 161 | 162 | @Override 163 | public void onItemSelected(AdapterView parent, View view, int position, long id) { 164 | arrayAdapter.setSelectedPos(position); 165 | posIdEdt.setText(getResources().getStringArray(R.array.native_ad_unified_ad_value)[position]); 166 | } 167 | 168 | @Override 169 | public void onNothingSelected(AdapterView parent) { 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/NativeExpressADActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.AdapterView; 9 | import android.widget.CheckBox; 10 | import android.widget.CompoundButton; 11 | import android.widget.EditText; 12 | import android.widget.Spinner; 13 | 14 | import com.qq.e.ads.cfg.VideoOption; 15 | import com.qq.e.union.demo.adapter.PosIdArrayAdapter; 16 | import com.qq.e.union.demo.util.ToastUtil; 17 | 18 | import static com.qq.e.union.demo.Constants.VIDEO_DURATION_SETTING_MAX; 19 | import static com.qq.e.union.demo.Constants.VIDEO_DURATION_SETTING_MIN; 20 | 21 | /** 22 | * Created by hechao on 2018/2/8. 23 | */ 24 | 25 | public class NativeExpressADActivity extends BaseActivity implements CompoundButton.OnCheckedChangeListener, AdapterView.OnItemSelectedListener { 26 | 27 | private static final String TAG = "NativeExpressADActivity"; 28 | public static final int DEFAULT_ITEMS_PER_AD = 10; // 每间隔10个条目插入一条广告 29 | 30 | private CheckBox btnNoOption; 31 | private CheckBox btnMute; 32 | private Spinner networkSpinner; 33 | private EditText posIdEdt; 34 | 35 | private Spinner spinner; 36 | private PosIdArrayAdapter arrayAdapter; 37 | 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_native_express_ad); 42 | /** 43 | * 如果选择支持视频的模板样式,请使用{@link PositionId#NATIVE_EXPRESS_SUPPORT_VIDEO_POS_ID} 44 | */ 45 | posIdEdt = findViewById(R.id.posId); 46 | 47 | spinner = findViewById(R.id.id_spinner); 48 | arrayAdapter = new PosIdArrayAdapter(this, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.native_express_video_ad)); 49 | arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 50 | spinner.setAdapter(arrayAdapter); 51 | spinner.setOnItemSelectedListener(this); 52 | 53 | btnNoOption = findViewById(R.id.cb_none_video_option); 54 | btnNoOption.setOnCheckedChangeListener(this); 55 | btnMute = findViewById(R.id.btn_mute); 56 | networkSpinner = findViewById(R.id.spinner_network); 57 | } 58 | 59 | /** 60 | * 如果选择支持视频的模板样式,请使用{@link PositionId#NATIVE_EXPRESS_SUPPORT_VIDEO_POS_ID} 61 | */ 62 | protected String getPosId() { 63 | String posId = ((EditText) findViewById(R.id.posId)).getText().toString(); 64 | return TextUtils.isEmpty(posId) ? PositionId.NATIVE_EXPRESS_POS_ID : posId; 65 | } 66 | 67 | private int getItemsPerAd() { 68 | String itemsPerAd = ((EditText) findViewById(R.id.items_per_ad)).getText().toString(); 69 | return TextUtils.isEmpty(itemsPerAd) ? DEFAULT_ITEMS_PER_AD : Integer.parseInt(itemsPerAd); 70 | } 71 | 72 | 73 | private int getMinVideoDuration() { 74 | if (((CheckBox) findViewById(R.id.cbMinVideoDuration)).isChecked()) { 75 | try { 76 | int rst = 77 | Integer.parseInt(((EditText) findViewById(R.id.etMinVideoDuration)).getText().toString()); 78 | if (rst > 0) { 79 | return rst; 80 | } else { 81 | ToastUtil.l("最小视频时长输入须大于0!"); 82 | } 83 | } catch (NumberFormatException e) { 84 | ToastUtil.l("最小视频时长输入不是整数!"); 85 | } 86 | } 87 | return 0; 88 | } 89 | 90 | private int getMaxVideoDuration() { 91 | if (((CheckBox) findViewById(R.id.cbMaxVideoDuration)).isChecked()) { 92 | try { 93 | int rst = Integer.parseInt(((EditText) findViewById(R.id.etMaxVideoDuration)).getText() 94 | .toString()); 95 | if (rst >= VIDEO_DURATION_SETTING_MIN && rst <= VIDEO_DURATION_SETTING_MAX) { 96 | return rst; 97 | } else { 98 | ToastUtil.l("最大视频时长输入不在有效区间内!"); 99 | } 100 | } catch (NumberFormatException e) { 101 | ToastUtil.l("最大视频时长输入不是整数!"); 102 | } 103 | } 104 | return 0; 105 | } 106 | 107 | private int getAdCount() { 108 | String string = ((EditText) findViewById(R.id.load_ad_count)).getText().toString(); 109 | if (TextUtils.isEmpty(string)) { 110 | return 0; 111 | } 112 | return Integer.parseInt(string); 113 | } 114 | 115 | public void onNormalViewClicked(View view) { 116 | Intent intent = new Intent(); 117 | intent.setClass(this, NativeExpressDemoActivity.class); 118 | putExtraToIntent(intent); 119 | startActivity(intent); 120 | } 121 | 122 | public void onRecyclerViewClicked(View view) { 123 | Intent intent = new Intent(); 124 | intent.setClass(this, NativeExpressRecyclerViewActivity.class); 125 | putExtraToIntent(intent); 126 | startActivity(intent); 127 | } 128 | 129 | public void onImmersiveClicked(View view) { 130 | Intent intent = new Intent(); 131 | intent.setClass(this, NativeExpressImmersiveActivity.class); 132 | putExtraToIntent(intent); 133 | startActivity(intent); 134 | } 135 | 136 | protected void putExtraToIntent(Intent intent){ 137 | intent.putExtra(Constants.POS_ID, getPosId()); 138 | Log.d(TAG, "BiddingToken: " + mS2sBiddingToken); 139 | intent.putExtra(Constants.TOKEN, mS2sBiddingToken); 140 | intent.putExtra(Constants.MIN_VIDEO_DURATION, getMinVideoDuration()); 141 | intent.putExtra(Constants.MAX_VIDEO_DURATION, getMaxVideoDuration()); 142 | if(btnNoOption.isChecked()){ 143 | intent.putExtra(Constants.NONE_OPTION, true); 144 | }else{ 145 | intent.putExtra(Constants.PLAY_MUTE, btnMute.isChecked()); 146 | intent.putExtra(Constants.PLAY_NETWORK, networkSpinner.getSelectedItemPosition()); 147 | } 148 | intent.putExtra(Constants.ITEMS_PER_AD, getItemsPerAd()); 149 | intent.putExtra(Constants.LOAD_AD_COUNT, getAdCount()); 150 | } 151 | 152 | @Override 153 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 154 | if (buttonView == btnNoOption) { 155 | networkSpinner.setEnabled(!isChecked); 156 | btnMute.setEnabled(!isChecked); 157 | } 158 | } 159 | 160 | public static VideoOption getVideoOption(Intent intent) { 161 | if(intent == null){ 162 | return null; 163 | } 164 | 165 | VideoOption videoOption = null; 166 | boolean noneOption = intent.getBooleanExtra(Constants.NONE_OPTION, false); 167 | if (!noneOption) { 168 | VideoOption.Builder builder = new VideoOption.Builder(); 169 | 170 | builder.setAutoPlayPolicy(intent.getIntExtra(Constants.PLAY_NETWORK, VideoOption.AutoPlayPolicy.ALWAYS)); 171 | builder.setAutoPlayMuted(intent.getBooleanExtra(Constants.PLAY_MUTE, true)); 172 | 173 | videoOption = builder.build(); 174 | } 175 | return videoOption; 176 | } 177 | 178 | @Override 179 | public void onItemSelected(AdapterView parent, View view, int position, long id) { 180 | arrayAdapter.setSelectedPos(position); 181 | posIdEdt.setText(getResources().getStringArray(R.array.native_express_video_ad_value)[position]); 182 | } 183 | 184 | @Override 185 | public void onNothingSelected(AdapterView parent) { 186 | 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/PositionId.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | /** 4 | * demo工程的广告位id 5 | * Created by chaotao on 2019-06-20 . 6 | **/ 7 | public class PositionId { 8 | public static final String BANNER_POS_ID = "9079537218417626401"; 9 | public static final String INTERTERISTAL_POS_ID = "8575134060152130849"; 10 | public static final String SPLASH_POS_ID = "9093517612222759"; 11 | public static final String NATIVE_POS_ID = "5010320697302671"; 12 | public static final String NATIVE_VIDEO_POS_ID = "3040990202714940"; 13 | public static final String NATIVE_PICTURE_VIDEO_POS_ID = "9040092262296093"; 14 | public static final String NATIVE_EXPRESS_POS_ID = "7030020348049331"; // 7030020348049331 15 | public static final String NATIVE_EXPRESS_POS_ID_VIDEO = "6090892202222287"; // 7030020348049331 16 | public static final String NATIVE_EXPRESS_POS_ID_PICTURE_VIDEO = "8040197282727229"; // 7030020348049331 17 | 18 | //如果选择支持视频的模板样式,请使用NativeExpressSupportVideoPosID测试广告位拉取 19 | public static final String NATIVE_UNIFIED_POS_ID = "9091145780212745"; // 6040749702835933 20 | public static final String NATIVE_UNIFIED_POS_ID_ONLY_HORIZONTAL = "7050291272634146"; 21 | public static final String NATIVE_UNIFIED_POS_ID_ONLY_VERTICAL = "2060699242425877"; 22 | public static final String NATIVE_UNIFIED_PICTURE_VIDEO_POS_ID = "9020995282824131"; 23 | public static final String NATIVE_UNIFIED_VERTICAL_POS_ID = "9000662439294066"; //竖版视频广告位 24 | public static final String NATIVE_EXPRESS_SUPPORT_VIDEO_POS_ID = "2000629911207832"; 25 | //支持视频模板样式的广告位 26 | public static final String CONTENT_AD_POS_ID = "5060323935699523"; 27 | public static final String REWARD_VIDEO_AD_POS_ID_SUPPORT_H = "2090845242931421";//支持竖版出横版视频 28 | public static final String REWARD_VIDEO_AD_POS_ID_UN_SUPPORT_H = "4000898212322043";//不支持竖版出横版视频 29 | public static final String UNIFIED_BANNER_POS_ID = "2105221344575643"; 30 | public static final String UNIFIED_VIDEO_PICTURE_ID_LARGE = "4080298282218338"; //图文+视频 大规格 31 | public static final String UNIFIED_VIDEO_PICTURE_ID_SMALL = "1050691202717808";//图文+视频 小规格 32 | //视频,大规格(竖版视频) 33 | public static final String UNIFIED_VIDEO_VIDEO_ID_LARGE_VERTICAL = "4090398252717676"; 34 | //视频,小规格 (横版视频) 35 | public static final String UNIFIED_VIDEO_VIDEO_ID_LARGE_HORIZONTAL = "4090791272610625"; 36 | public static final String UNIFIED_INTERSTITIAL_ID_ONLY_SMALL2 = "8020259898964453";// 只小规格 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/SDKVersionActivity.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import androidx.annotation.Nullable; 6 | import android.widget.TextView; 7 | 8 | import com.qq.e.comm.managers.status.SDKStatus; 9 | 10 | /** 11 | * 版本号展示 Activity 12 | */ 13 | public class SDKVersionActivity extends BaseActivity { 14 | @Override 15 | protected void onCreate(@Nullable Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_sdk_version); 18 | ((TextView) findViewById(R.id.sdk_version_txt)) 19 | .setText("SDk version is : " + SDKStatus.getIntegrationSDKVersion()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/adapter/PosIdArrayAdapter.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.adapter; 2 | 3 | import android.content.Context; 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ArrayAdapter; 9 | import android.widget.TextView; 10 | 11 | public class PosIdArrayAdapter extends ArrayAdapter { 12 | 13 | private int selectedPos; 14 | 15 | public void setSelectedPos(int selectedPos) { 16 | this.selectedPos = selectedPos; 17 | } 18 | 19 | public PosIdArrayAdapter(@NonNull Context context, int resource, @NonNull Object[] objects) { 20 | super(context, resource, objects); 21 | } 22 | 23 | public PosIdArrayAdapter(@NonNull Context context, int resource, int textViewResourceId) { 24 | super(context, resource, textViewResourceId); 25 | } 26 | 27 | @Override 28 | public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { 29 | View view = super.getDropDownView(position, convertView, parent); 30 | TextView textView = (TextView) view; 31 | if (this.selectedPos == position) { 32 | textView.setTextColor(0xff373741); 33 | textView.getPaint().setFakeBoldText(true); 34 | } else { 35 | textView.setTextColor(0xff6d6d6d); 36 | textView.getPaint().setFakeBoldText(false); 37 | } 38 | return view; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/DemoRequestUtils.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import com.qq.e.comm.managers.GDTAdSdk; 7 | 8 | import org.json.JSONObject; 9 | 10 | import java.io.BufferedOutputStream; 11 | import java.io.BufferedReader; 12 | import java.io.ByteArrayOutputStream; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.io.OutputStream; 17 | import java.net.HttpURLConnection; 18 | import java.net.URL; 19 | import java.nio.charset.Charset; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.concurrent.ExecutorService; 23 | import java.util.concurrent.Executors; 24 | 25 | /** 26 | * Server bidding 模拟请求服务端进行比价的工具类 27 | */ 28 | public class DemoRequestUtils { 29 | public static final ExecutorService SINGLE_THREAD_EXECUTOR = 30 | Executors.newSingleThreadExecutor(r -> new Thread(r, "BIDDING_THREAD")); 31 | private static final String TAG = DemoRequestUtils.class.getSimpleName(); 32 | protected static final String SERVER_BIDDING_URL = "https://mi.gdt.qq.com/server_bidding"; 33 | private static final String POST_DATA = "{\"id\":\"5f0417f6354b680001e94518\",\"imp\":[{\"id\":\"1\"," + 34 | "\"video\":{\"minduration\":0,\"maxduration\":46,\"w\":720,\"h\":1422,\"linearity\":1,\"minbitrate\":250," + 35 | "\"maxbitrate\":15000,\"ext\":{\"skip\":0,\"videotype\":\"rewarded\",\"rewarded\":1}},\"tagid\":\"POSID\"," + 36 | "\"bidfloor\":1,\"bidfloorcur\":\"CNY\",\"secure\":1}],\"app\":{\"id\":\"5afa947e9c8119360fba1bea\"," + 37 | "\"name\":\"VungleApp123\",\"bundle\":\"com.qq.e.union.demo.union\"},\"device\":{\"ua\":\"Mozilla/5.0 (Linux; " + 38 | "Android 9; SM-A207F Build/PPR1.180610.011; wv) AppleWebKit/537.36 KHTML, like Gecko) Version/4.0 Chrome/74.0" + 39 | ".3729.136 Mobile Safari/537.36\",\"geo\":{\"lat\":-7.2484,\"lon\":112.7419},\"ip\":\"115.178.227.128\"," + 40 | "\"devicetype\":1,\"make\":\"samsung\",\"model\":\"SM-A207F\",\"os\":\"android\",\"osv\":\"9\",\"h\":1422," + 41 | "\"w\":720,\"language\":\"en\",\"connectiontype\":2,\"ifa\":\"dd94e183d8790d057fc73d9c761ea2fa\"," + 42 | "\"ext\":{\"oaid" + 43 | "\":\"0176863C3B9A5E419BCAF702B37BEFB38B8D05CEA84022FB76BD723BA89D2ED2116F960A73FE1FFB12499E31EF664F5EAE87386F19D8A41390FEBAA5362042BC7A601D4CB006DA4E66\"}},\"cur\":[\"CNY\"],\"ext\":{\"buyer_id\":\"TOKEN\",\"sdk_info\":\"SDK_INFO\"}}"; 44 | 45 | 46 | public void requestBiddingToken(String posId, RequestCallBack callBack) { 47 | SINGLE_THREAD_EXECUTOR.execute(() -> { 48 | try { 49 | HttpURLConnection connection = 50 | (HttpURLConnection) new URL(SERVER_BIDDING_URL).openConnection(); 51 | connection.setDoOutput(true); 52 | for (Map.Entry entry : getRequestProperty().entrySet()) { 53 | connection.setRequestProperty(entry.getKey(), entry.getValue()); 54 | } 55 | String postData = getPostData(posId); 56 | Log.d(TAG, "post_data: " + postData); 57 | byte[] postDataBytes = postData.getBytes(Charset.forName("UTF-8")); 58 | if (postDataBytes != null && postDataBytes.length > 0) { 59 | OutputStream out = new BufferedOutputStream(connection.getOutputStream()); 60 | out.write(postDataBytes); 61 | out.flush(); 62 | out.close(); 63 | } 64 | handleResponse(getStringContent(connection), callBack); 65 | } catch (IOException e) { 66 | ToastUtil.s("请求 token 失败: " + e.getMessage()); 67 | e.printStackTrace(); 68 | } 69 | }); 70 | } 71 | 72 | protected String getPostData(String posId) { 73 | Map map = new HashMap<>(); 74 | map.put("staIn", "com.qq.e.union.demo.view.S2SBiddingDemoUtils"); // 开发者自定义参数,默认不传 75 | String buyerId = GDTAdSdk.getGDTAdManger().getBuyerId(map); 76 | String sdkInfo = GDTAdSdk.getGDTAdManger().getSDKInfo(posId); 77 | Log.d(TAG, "sdk_info: " + sdkInfo); 78 | return POST_DATA.replace("POSID", posId) 79 | .replace("TOKEN", buyerId) 80 | .replace("SDK_INFO", sdkInfo); 81 | } 82 | 83 | protected Map getRequestProperty() { 84 | Map map = new HashMap<>(); 85 | map.put("Content-Type", "application/json"); 86 | map.put("User-Agent", "GDTMobApp/0 CFNetwork/1220.1 Darwin/19.6.0"); 87 | map.put("Accept", "application/json"); 88 | map.put("Accept-Language", "en-us"); 89 | map.put("X-OpenRTB-Version", "2.5"); 90 | return map; 91 | } 92 | 93 | protected void handleResponse(String response, RequestCallBack callBack) { 94 | try { 95 | JSONObject jsonObject = new JSONObject(response); 96 | String token = jsonObject.optString("token"); 97 | if (TextUtils.isEmpty(token)) { 98 | ToastUtil.s("回包中无 token"); 99 | } else { 100 | ToastUtil.s("请求 token 成功"); 101 | if (callBack != null) { 102 | Log.d(TAG, "requestBiddingToken: " + callBack); 103 | callBack.onSuccess(token); 104 | } 105 | } 106 | } catch (Exception e) { 107 | ToastUtil.s("请求 token 失败"); 108 | Log.e("requestBiddingToken", e.getMessage()); 109 | } 110 | } 111 | 112 | public void requestAppInfo(String url, RequestCallBack callBack) { 113 | if (TextUtils.isEmpty(url)) { 114 | return; 115 | } 116 | SINGLE_THREAD_EXECUTOR.execute(() -> { 117 | try { 118 | HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); 119 | connection.setRequestMethod("GET"); 120 | connection.connect(); 121 | String result = getStringContent(connection); 122 | callBack.onSuccess(result); 123 | } catch (IOException e) { 124 | ToastUtil.s("请求 AppInfo 失败"); 125 | } 126 | }); 127 | } 128 | 129 | 130 | private static byte[] getBytesContent(HttpURLConnection connection) throws IllegalStateException 131 | , IOException { 132 | InputStream in = connection.getInputStream(); 133 | ByteArrayOutputStream bo = new ByteArrayOutputStream(); 134 | try { 135 | byte[] buffer = new byte[1024]; 136 | int len = 0; 137 | while ((len = (in.read(buffer))) > 0) { 138 | bo.write(buffer, 0, len); 139 | } 140 | } finally { 141 | try { 142 | if (in != null) { 143 | in.close(); 144 | } 145 | } catch (IOException ignore) { 146 | } 147 | } 148 | return bo.toByteArray(); 149 | } 150 | 151 | private static String getStringContent(HttpURLConnection connection) throws IOException { 152 | byte[] bytes = getBytesContent(connection); 153 | if (bytes == null) { 154 | return null; 155 | } else if (bytes.length == 0) { 156 | return ""; 157 | } 158 | 159 | String charset = null; 160 | try { 161 | charset = connection.getContentEncoding(); 162 | } catch (Exception e) { 163 | e.printStackTrace(); 164 | } 165 | if (charset == null) { 166 | charset = "UTF-8"; 167 | } 168 | return new String(bytes, charset); 169 | } 170 | 171 | public interface RequestCallBack { 172 | void onSuccess(String result); 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/DownloadApkConfirmDialogWebView.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.res.Configuration; 7 | import android.text.TextUtils; 8 | import android.util.Log; 9 | import android.view.Gravity; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.Window; 13 | import android.view.WindowManager; 14 | import android.webkit.WebResourceError; 15 | import android.webkit.WebResourceRequest; 16 | import android.webkit.WebView; 17 | import android.webkit.WebViewClient; 18 | import android.widget.Button; 19 | import android.widget.FrameLayout; 20 | import android.widget.ImageView; 21 | import android.widget.ProgressBar; 22 | 23 | import com.qq.e.comm.compliance.DownloadConfirmCallBack; 24 | import com.qq.e.union.demo.R; 25 | 26 | 27 | /* 28 | * created by timfeng 2020/8/21 29 | */ 30 | public class DownloadApkConfirmDialogWebView extends Dialog implements View.OnClickListener { 31 | private static final String TAG = "ConfirmDialogWebView"; 32 | private Context context; 33 | private int orientation; 34 | private DownloadConfirmCallBack callBack; 35 | private WebView webView; 36 | private ImageView close; 37 | private Button confirm; 38 | 39 | private ViewGroup contentHolder; 40 | private ProgressBar loadingBar; 41 | private Button reloadButton; 42 | 43 | private String url; 44 | private boolean urlLoadError = false; 45 | 46 | private static final String RELOAD_TEXT = "重新加载"; 47 | private static final String LOAD_ERROR_TEXT = "抱歉,应用信息获取失败"; 48 | 49 | public DownloadApkConfirmDialogWebView(Context context, String infoUrl, 50 | DownloadConfirmCallBack callBack) { 51 | super(context, R.style.DownloadConfirmDialogFullScreen);//需要全屏显示,同时显示非窗口蒙版 52 | this.context = context; 53 | this.callBack = callBack; 54 | this.url = infoUrl; 55 | orientation = context.getResources().getConfiguration().orientation; 56 | requestWindowFeature(Window.FEATURE_NO_TITLE); 57 | setCanceledOnTouchOutside(true); 58 | initView(); 59 | } 60 | 61 | private void initView() { 62 | setContentView(R.layout.download_confirm_dialog); 63 | View root = findViewById(R.id.download_confirm_root); 64 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 65 | root.setBackgroundResource(R.drawable.download_confirm_background_portrait); 66 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 67 | root.setBackgroundResource(R.drawable.download_confirm_background_landscape); 68 | } 69 | close = findViewById(R.id.download_confirm_close); 70 | close.setOnClickListener(this); 71 | reloadButton = findViewById(R.id.download_confirm_reload_button); 72 | reloadButton.setOnClickListener(this); 73 | confirm = findViewById(R.id.download_confirm_confirm); 74 | confirm.setOnClickListener(this); 75 | loadingBar = findViewById(R.id.download_confirm_progress_bar); 76 | contentHolder = findViewById(R.id.download_confirm_content); 77 | createTextView(); 78 | } 79 | 80 | private void createTextView(){ 81 | FrameLayout layout = findViewById(R.id.download_confirm_holder); 82 | webView = new WebView(context); 83 | webView.getSettings().setJavaScriptEnabled(true); 84 | webView.setWebViewClient(new Client()); 85 | layout.addView(webView); 86 | } 87 | @Override 88 | public void show() { 89 | super.show(); 90 | try { 91 | loadUrl(url); 92 | } catch (Exception e) { 93 | Log.e(DownloadApkConfirmDialogWebView.TAG, "load error url:" + url, e); 94 | } 95 | } 96 | 97 | 98 | private void loadUrl(String url) { 99 | if (TextUtils.isEmpty(url)) { 100 | loadingBar.setVisibility(View.GONE); 101 | contentHolder.setVisibility(View.GONE); 102 | reloadButton.setVisibility(View.VISIBLE); 103 | reloadButton.setText(LOAD_ERROR_TEXT); 104 | reloadButton.setEnabled(false); 105 | return; 106 | } 107 | urlLoadError = false; 108 | Log.d(TAG, "download confirm load url:" + url); 109 | webView.loadUrl(url); 110 | } 111 | 112 | public void setInstallTip() { 113 | confirm.setText("立即安装"); 114 | } 115 | 116 | @Override 117 | protected void onStart() { 118 | int height = PxUtils.getDeviceHeightInPixel(context); 119 | int width = PxUtils.getDeviceWidthInPixel(context); 120 | Window window = getWindow(); 121 | window.getDecorView().setPadding(0, 0, 0, 0); 122 | WindowManager.LayoutParams layoutParams = window.getAttributes(); 123 | if (orientation == Configuration.ORIENTATION_PORTRAIT) { 124 | layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; 125 | layoutParams.height = (int) (height * 0.6); 126 | layoutParams.gravity = Gravity.BOTTOM; 127 | layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationUp; 128 | } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { 129 | layoutParams.width = (int) (width * 0.5); 130 | layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; 131 | layoutParams.gravity = Gravity.RIGHT; 132 | layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationRight; 133 | } 134 | //弹窗外区域蒙版50%透明度 135 | layoutParams.dimAmount = 0.5f; 136 | 137 | //resume后动画会重复,在显示出来后重置无动画 138 | window.setAttributes(layoutParams); 139 | setOnShowListener(new OnShowListener() { 140 | @Override 141 | public void onShow(DialogInterface dialog) { 142 | try { 143 | Window window = getWindow(); 144 | window.setWindowAnimations(0); 145 | } catch (Throwable t) { 146 | } 147 | } 148 | }); 149 | } 150 | 151 | @Override 152 | public void onClick(View v) { 153 | if (v == close) { 154 | if (callBack != null) { 155 | callBack.onCancel(); 156 | } 157 | dismiss(); 158 | } else if (v == confirm) { 159 | if (callBack != null) { 160 | callBack.onConfirm(); 161 | } 162 | dismiss(); 163 | } else if (v == reloadButton) { 164 | loadUrl(url); 165 | } 166 | 167 | } 168 | 169 | @Override 170 | public void cancel() { 171 | super.cancel(); 172 | if (callBack != null) { 173 | callBack.onCancel(); 174 | } 175 | } 176 | 177 | class Client extends WebViewClient { 178 | @Override 179 | public void onPageFinished(WebView view, String url) { 180 | super.onPageFinished(view, url); 181 | if (!urlLoadError) { 182 | loadingBar.setVisibility(View.GONE); 183 | reloadButton.setVisibility(View.GONE); 184 | contentHolder.setVisibility(View.VISIBLE); 185 | } 186 | } 187 | 188 | @Override 189 | public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { 190 | super.onReceivedError(view, request, error); 191 | Log.d(TAG, "doConfirmWithInfo onReceivedError:" + error + " " + request); 192 | urlLoadError = true; 193 | loadingBar.setVisibility(View.GONE); 194 | contentHolder.setVisibility(View.GONE); 195 | reloadButton.setVisibility(View.VISIBLE); 196 | reloadButton.setText(RELOAD_TEXT); 197 | reloadButton.setEnabled(true); 198 | } 199 | } 200 | 201 | 202 | } 203 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/MainHandler.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | public class MainHandler { 7 | 8 | private static final Looper mainLooper = Looper.getMainLooper(); 9 | private static Handler mainHandler; 10 | 11 | private static Handler getMain() { 12 | if (mainHandler == null) { 13 | mainHandler = new Handler(mainLooper); 14 | } 15 | return mainHandler; 16 | } 17 | 18 | public static boolean postIfNotMain(Runnable r) { 19 | if (r == null) { 20 | return false; 21 | } 22 | if (Thread.currentThread() == mainLooper.getThread()) { 23 | r.run(); 24 | return true; 25 | } else { 26 | return post(r); 27 | } 28 | } 29 | 30 | public static boolean post(Runnable r) { 31 | return getMain().post(r); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/PxUtils.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.util.DisplayMetrics; 6 | import android.util.TypedValue; 7 | 8 | public class PxUtils { 9 | 10 | public static int dpToPx(Context context, int dp) { 11 | Resources r = context.getApplicationContext().getResources(); 12 | float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); 13 | return (int) px; 14 | } 15 | 16 | public static int pxToDp(Context context, int px) { 17 | float scale = context.getApplicationContext().getResources().getDisplayMetrics().density; 18 | return (int) (px / scale + 0.5f); 19 | } 20 | 21 | public static float dpToPx(Context context, float dp) { 22 | Resources r = context.getApplicationContext().getResources(); 23 | float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); 24 | return px; 25 | } 26 | 27 | public static float pxToDp(Context context, float px) { 28 | float scale = context.getApplicationContext().getResources().getDisplayMetrics().density; 29 | return (px / scale + 0.5f); 30 | } 31 | 32 | public static int getDeviceWidthInPixel(Context context) { 33 | DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); 34 | return dm.widthPixels; 35 | } 36 | 37 | public static int getDeviceHeightInPixel(Context context) { 38 | DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); 39 | return dm.heightPixels; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.app.Activity; 4 | import android.content.pm.ActivityInfo; 5 | import android.view.WindowManager; 6 | 7 | 8 | import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 9 | import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 10 | 11 | public class ScreenUtils { 12 | 13 | public static void toggleOrientation(Activity activity) { 14 | int currentOrientation = activity.getResources().getConfiguration().orientation; 15 | if (currentOrientation == ORIENTATION_PORTRAIT) { 16 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 17 | } else if (currentOrientation == ORIENTATION_LANDSCAPE) { 18 | activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 19 | } 20 | } 21 | 22 | public static void toggleFullscreen(Activity activity) { 23 | boolean isFullscreen = (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) 24 | == WindowManager.LayoutParams.FLAG_FULLSCREEN; 25 | if (isFullscreen) { 26 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 27 | } else { 28 | activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 29 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/SplashZoomOutLayout.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.GradientDrawable; 5 | import android.os.Build; 6 | import android.view.MotionEvent; 7 | import android.view.View; 8 | import android.view.ViewConfiguration; 9 | import android.view.ViewGroup; 10 | import android.widget.FrameLayout; 11 | 12 | public class SplashZoomOutLayout extends FrameLayout { 13 | private float dX, dY; 14 | private int margin; 15 | private int maxX; 16 | private int maxY; 17 | 18 | private float moveAccumulateX, moveAccumulateY; 19 | private final int touchSlop;//拖动和点击的触发阈值,采用系统的参数,超过该值认为是拖动,低于认为是点击 20 | 21 | public SplashZoomOutLayout(Context context, int m) { 22 | super(context); 23 | //设置悬浮窗的圆角 24 | GradientDrawable gd = new GradientDrawable(); 25 | gd.setCornerRadius(10); 26 | this.setBackgroundDrawable(gd); 27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 28 | setClipToOutline(true); 29 | } 30 | this.margin = m; 31 | touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 32 | } 33 | 34 | @Override 35 | protected void onAttachedToWindow() { 36 | super.onAttachedToWindow(); 37 | this.post(new Runnable() { 38 | @Override 39 | public void run() { 40 | View parent = (View) getParent(); 41 | if (parent == null) { 42 | return; 43 | } 44 | int parentWidth = parent.getWidth(); 45 | int parentHeight = parent.getHeight(); 46 | maxY = parentHeight - SplashZoomOutLayout.this.getHeight() - margin; 47 | maxX = parentWidth - SplashZoomOutLayout.this.getWidth() - margin; 48 | } 49 | }); 50 | } 51 | 52 | @Override 53 | public boolean onInterceptTouchEvent(MotionEvent event) { 54 | switch (event.getAction()) { 55 | 56 | case MotionEvent.ACTION_DOWN: 57 | dX = getX() - event.getRawX(); 58 | dY = getY() - event.getRawY(); 59 | moveAccumulateX = 0; 60 | moveAccumulateY = 0; 61 | break; 62 | 63 | case MotionEvent.ACTION_MOVE: 64 | float newX = event.getRawX() + dX; 65 | float newY = event.getRawY() + dY; 66 | 67 | //这里采用累积,防止转一圈回到起点的情况也触发点击 68 | moveAccumulateX += Math.abs(newX - getX()); 69 | moveAccumulateY += Math.abs(newY - getY()); 70 | //限制浮窗不会超出父布局 71 | newX = newX < margin ? margin : newX > maxX ? maxX : newX; 72 | newY = newY < margin ? margin : newY > maxY ? maxY : newY; 73 | animate() 74 | .x(newX) 75 | .y(newY) 76 | .setDuration(0) 77 | .start(); 78 | break; 79 | case MotionEvent.ACTION_UP: 80 | case MotionEvent.ACTION_CANCEL: 81 | float deltaX = 0f, deltaY = 0f; 82 | 83 | int leftMargin = 0, topMargin = 0, rightMargin = 0, bottomMargin = 0; 84 | ViewGroup.LayoutParams layoutParams = getLayoutParams(); 85 | if (layoutParams instanceof ViewGroup.MarginLayoutParams) { 86 | leftMargin = ((ViewGroup.MarginLayoutParams) layoutParams).leftMargin; 87 | topMargin = ((ViewGroup.MarginLayoutParams) layoutParams).topMargin; 88 | rightMargin = ((ViewGroup.MarginLayoutParams) layoutParams).rightMargin; 89 | bottomMargin = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin; 90 | } 91 | 92 | ViewGroup parent = (ViewGroup) getParent(); 93 | int parentWidth = parent.getWidth(); 94 | int parentHeight = parent.getHeight(); 95 | 96 | if (getX() < leftMargin) { 97 | deltaX = leftMargin - getX(); 98 | } else if (getX() + getWidth() + rightMargin > parentWidth) { 99 | deltaX = parentWidth - (getX() + getWidth() + rightMargin); 100 | } 101 | 102 | if (getY() < topMargin) { 103 | deltaY = topMargin - getY(); 104 | } else if (getY() + getHeight() + bottomMargin > parentHeight) { 105 | deltaY = parentHeight - (getY() + getHeight() + bottomMargin); 106 | } 107 | 108 | animate() 109 | .translationXBy(deltaX) 110 | .translationYBy(deltaY) 111 | .setDuration(0) 112 | .start(); 113 | //如果拖动超过一定距离拦截发向子view的点击事件 114 | if (moveAccumulateX > touchSlop || moveAccumulateY > touchSlop) { 115 | return true; 116 | } 117 | default: 118 | } 119 | return super.onInterceptTouchEvent(event); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/util/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.util; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.widget.Toast; 6 | 7 | import com.qq.e.union.demo.DemoApplication; 8 | 9 | public class ToastUtil { 10 | 11 | private static final Looper sMainLooper = Looper.getMainLooper(); 12 | private static final Handler sMainHandler = new Handler(sMainLooper); 13 | 14 | public static void s(String msg) { 15 | if (Thread.currentThread() == sMainLooper.getThread()) { 16 | showToast(msg, Toast.LENGTH_SHORT); 17 | } else { 18 | sMainHandler.post(() -> showToast(msg, Toast.LENGTH_SHORT)); 19 | } 20 | } 21 | 22 | public static void l(String msg) { 23 | if (Thread.currentThread() == sMainLooper.getThread()) { 24 | showToast(msg, Toast.LENGTH_LONG); 25 | } else { 26 | sMainHandler.post(() -> showToast(msg, Toast.LENGTH_LONG)); 27 | } 28 | } 29 | 30 | private static void showToast(String msg, int duration) { 31 | Toast.makeText(DemoApplication.getAppContext(), msg, duration).show(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/view/FullScreenVideoView.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.SurfaceHolder; 6 | import android.widget.VideoView; 7 | 8 | public class FullScreenVideoView extends VideoView { 9 | 10 | public FullScreenVideoView(Context context) { 11 | super(context); 12 | init(); 13 | } 14 | 15 | public FullScreenVideoView(Context context, AttributeSet attrs) { 16 | super(context, attrs); 17 | init(); 18 | } 19 | 20 | public FullScreenVideoView(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | init(); 23 | } 24 | 25 | /** 26 | * 解决在android 12 video播放过程中会缩小的问题 27 | */ 28 | private void init() { 29 | SurfaceHolder holder = getHolder(); 30 | if (holder == null) { 31 | return; 32 | } 33 | holder.addCallback(new SurfaceHolder.Callback() { 34 | @Override 35 | public void surfaceCreated(SurfaceHolder holder) { 36 | 37 | } 38 | 39 | @Override 40 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 41 | holder.setFixedSize(getMeasuredWidth(), getMeasuredHeight()); 42 | } 43 | 44 | @Override 45 | public void surfaceDestroyed(SurfaceHolder holder) { 46 | 47 | } 48 | }); 49 | } 50 | 51 | 52 | @Override 53 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 54 | int width = getDefaultSize(0, widthMeasureSpec); 55 | int height = getDefaultSize(0, heightMeasureSpec); 56 | setMeasuredDimension(width, height); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Demo/src/main/java/com/qq/e/union/demo/view/ViewUtils.java: -------------------------------------------------------------------------------- 1 | package com.qq.e.union.demo.view; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.view.ViewParent; 6 | 7 | public class ViewUtils { 8 | 9 | public static void removeFromParent(View view) { 10 | if (view != null) { 11 | ViewParent vp = view.getParent(); 12 | if (vp instanceof ViewGroup) { 13 | ((ViewGroup) vp).removeView(view); 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Demo/src/main/res/anim/download_confirm_dialog_slide_right_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/src/main/res/anim/download_confirm_dialog_slide_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable-sw600dp/gdt_splash_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable-sw600dp/gdt_splash_text.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable-xxhdpi/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable-xxhdpi/delete.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable-xxhdpi/icon_download_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable-xxhdpi/icon_download_gray.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable-xxhdpi/icon_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable-xxhdpi/icon_link.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable-xxhdpi/icon_to_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable-xxhdpi/icon_to_link.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/background_bottom_immersive_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/background_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/background_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/background_circle_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/download_confirm_background_confirm.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/download_confirm_background_landscape.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/download_confirm_background_portrait.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_ic_express_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_ic_express_close.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_icon.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_logo.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_logo_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_logo_white.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_splash_holder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_splash_holder.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/gdt_splash_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GDTMobSDK/GDTMobSDK-Android/507d866d169a7673fb157743dfb037c262b053af/Demo/src/main/res/drawable/gdt_splash_text.png -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/ic_download_confirm_close.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/shape_bg_call_to_action.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /Demo/src/main/res/drawable/shape_bg_countdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /Demo/src/main/res/layout/activity_demo_game.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 |