{"id":21462265,"url":"https://github.com/espoirx/easyadvapp","last_synced_at":"2025-07-15T03:30:50.346Z","repository":{"id":206506001,"uuid":"716838787","full_name":"EspoirX/EasyAdvApp","owner":"EspoirX","description":"穿山甲 融合 sdk 广告封装","archived":false,"fork":false,"pushed_at":"2023-12-25T03:39:03.000Z","size":145,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-12-25T04:28:27.223Z","etag":null,"topics":["adv","adversarial","advertisement","csj","easyadv","guanggao"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EspoirX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-11-10T01:27:15.000Z","updated_at":"2023-12-21T10:14:09.000Z","dependencies_parsed_at":"2023-12-25T04:26:50.115Z","dependency_job_id":"35b86ba3-dfed-4e8b-bb77-8cb9630b8013","html_url":"https://github.com/EspoirX/EasyAdvApp","commit_stats":null,"previous_names":["espoirx/easyadvapp"],"tags_count":3,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EspoirX%2FEasyAdvApp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EspoirX%2FEasyAdvApp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EspoirX%2FEasyAdvApp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EspoirX%2FEasyAdvApp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EspoirX","download_url":"https://codeload.github.com/EspoirX/EasyAdvApp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226012288,"owners_count":17559651,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adv","adversarial","advertisement","csj","easyadv","guanggao"],"created_at":"2024-11-23T07:13:21.960Z","updated_at":"2024-11-23T07:13:22.401Z","avatar_url":"https://github.com/EspoirX.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyAdvApp\n广告封装\n\nEasyAdv 封装了 穿山甲融合 sdk ，旨在使用广告时可以更加 Easy。\n\n## 可以解决什么问题：  \n1. 统一 API，一句话调用。\n2. 与业务分离，不需要关注广告实现，让你可以只关心业务开发\n3. 全局监听各种广告回调，可以统一处理一些埋点之类的操作，不需要写得到处都是。\n4. 总之，感觉还行。。\n\n## 用法：\n\n```groovy\ndependencies {\n    implementation 'com.github.EspoirX:EasyAdvApp:vX.X.x'\n}\n```\n[![](https://jitpack.io/v/EspoirX/EasyAdvApp.svg)](https://jitpack.io/#EspoirX/EasyAdvApp)\n\n### 初始化\n先导下基本的广告sdk，因为框架里面用的是 compileOnly\n\n```gradle\n implementation \"com.pangle.cn:mediation-sdk:5.7.0.5\"\n```\n\n```kotlin\nEasyAdv.init(this)\n    .sdkConfig {\n        context = this@MyApp\n        appId = \"KFC_V_WO_50\"\n        appName = \"EasyAdvApp\"\n        userId = \"123456\"\n        timeOutMillis = 3000 \n    }\n    .setGlobalAdvConfig {\n        enableHotSplashAdv = true\n        hotSplashAdvStrategy = TTHotSplashAdvStrategy()\n    }\n    .setPlatform(TTAdSdkPlatform())\n    .setSplashAdvEngine(TTSplashAdvEngine())\n    .apply()\n```\n\n如示例代码，通过 init 方法初始化，初始化后可配置各种配置，下面一一说明：  \n\n#### sdkConfig\n穿山甲 sdk 初始化时需要的参数，应该都知道吧.  \n其中 userId 是自己用户系统的 userId，因为初始化或者一些广告加载的时候需要传，当然看情况，不是必要参数。  \ntimeOutMillis 是sdk初始化超时时间，影响的是冷启动开屏广告，因为如果网络问题或者其他问题导致sdk初始化太久的话，不可能一直卡在开屏页，\n所以加个超时逻辑，不设置就是没有这逻辑。\n\n#### setGlobalAdvConfig\n配置一些全局的广告配置：  \n```kotlin\nclass GlobalAdvConfig {\n    var splashAdvListener: SplashAdvListener? = null\n    var fullScreenVideoAdvListener: FullScreenVideoAdvListener? = null\n    var bannerAdvListener: BannerAdvListener? = null\n    var feedAdvListener: FeedAdvListener? = null\n    var rewardVideoAdvListener: RewardVideoAdvListener? = null\n    var userId: String = \"\"\n    var enableHotSplashAdv = false\n    var hotSplashAdvStrategy: IHotSplashAdvStrategy? = null\n}\n```\n\n1. splashAdvListener 全局的开屏页广告回调监听\n2. fullScreenVideoAdvListener 全局的插屏广告回调监听\n3. bannerAdvListener 全局的Banner广告回调监听\n4. feedAdvListener 全局的信息流广告回调监听\n5. rewardVideoAdvListener 全局的激励广告回调监听\n6. userId 跟 sdkConfig 那说的一个意思\n7. enableHotSplashAdv 是否运行热启动开屏广告\n8. hotSplashAdvStrategy 热启动开屏广告实现方案，要结合 enableHotSplashAdv 为 true 才会生效\n\n#### setPlatform 设置一个 ISdkPlatform，广告sdk 将实现该接口进行初始化\n\n```kotlin\ninterface ISdkPlatform {\n    fun initAdvSdk(\n        builder: AdvSDKBuilder,\n        callback: AdvSdkInitCallback\n    )\n}\n```\n\n### setSplashAdvEngine ...\n```kotlin\nsetSplashAdvEngine(engine: ISplashAdvEngine)\nsetFullScreenVideoAdvEngine(engine: IFullScreenVideoAdvEngine)\nsetBannerAdvEngine(engine: IBannerAdvEngine)\nsetFeedAdvEngine(engine: IFeedAdvEngine)\nsetRewardVideoEngine(engine: IRewardVideoAdvEngine)\n```\n\n对应各种广告的实现，实现对应的接口即可。最后调用 apply() 完成初始化.\n\n### 显示广告\n以 开屏广告 为例，其他类型差不多。\n\n1. 首先实现 ISplashAdvEngine 接口，完成开屏广告具体的实现，主要是实现 showSplashAdv 方法（完整示例可以查看代码中的 TTSplashAdvEngine）\n```kotlin\nclass TTSplashAdvEngine : ISplashAdvEngine {\n    override fun showSplashAdv(config: SplashAdvConfig) {\n        val adNativeLoader = TTAdSdk.getAdManager().createAdNative(act)\n        val adSlot = AdSlot.Builder()\n            .setCodeId(config.codeId)\n            .setImageAcceptedSize(config.width, config.height)\n            .build()\n        adNativeLoader.loadSplashAd(adSlot, object : TTAdNative.SplashAdListener {\n            //...\n        }\n    }\n}\n```\n\n然后在开屏页直接调用展示即可：\n\n```kotlin\nEasyAdv.splashConfig()\n    .setCodeId(\"KFC_V_WO_50\")\n    .setActivity(this)\n    .setWidth(getScreenWidth())\n    .setHeight(getScreenHeight())\n    .lifecycle(this)\n    .scope(lifecycleScope)\n    .setContainer(findViewById\u003cFrameLayout\u003e(R.id.adLayout))\n    .setSplashAdvListener(onError = { _, _ -\u003e\n        toMain()\n    }, onAdClicked = { _, _ -\u003e\n        toMain()\n    }, onAdSkip = {\n        toMain()\n    }, onAdTimeOver = {\n       toMain()\n    })\n    .showSplashAdv()\n```\n\n如上，设置广告的 codeId，当前act（如果不是 act 的上下文，广告会显示不出来），常规宽高，广告 ViewGroup，各种回调等，最后调用 showSplashAdv 即可。\n\n在调用开屏广告的时候如果 sdk 还没初始化完成，showSplashAdv 会一直等待 sdk 初始化完成才会执行，所以不用担心时序问题。  \n当 sdk 初始化失败或者超时的时候，会回调 onError。回调方法除了常规的以外，还提供了 DSL 的方式（如上示例），要哪个再写哪个，提高代码的简洁度。\n\n** 热启动开屏广告 **\n\n先在初始化的时候将 enableHotSplashAdv 设为 true，然后实现 IHotSplashAdvStrategy 接口。\n\n```kotlin\ninterface IHotSplashAdvStrategy {\n    fun getCodeId(): String\n\n    fun showRequirement(activity: Activity): Boolean\n\n    fun showHotSplashAdv(activity: Activity, codeId: String)\n}\n```\n1. getCodeId 就是热启动广告的 codeId\n2. showRequirement 展示条件，比如说隔10分钟展示一次，哪些页面展示哪些不需要等，要是没条件直接返回 true 就行\n3. showHotSplashAdv 显示具体实现\n\n举例（演示了每隔10分钟显示一次热启动广告）：\n\n```kotlin\nclass TTHotSplashAdvStrategy : IHotSplashAdvStrategy {\n\n    private var lastShowTime = 0L\n    private var ttHotSplashAdvDialog: TTHotSplashAdvDialog? = null\n\n    override fun getCodeId(): String = \"KFC_V_WO_50\"\n\n    override fun showRequirement(activity: Activity): Boolean {\n        return activity !is SplashActivity\n                \u0026\u0026 System.currentTimeMillis() - lastShowTime \u003e 60 * 60 * 1000\n    }\n\n    override fun showHotSplashAdv(activity: Activity, codeId: String) {\n        lastShowTime = System.currentTimeMillis()\n        ttHotSplashAdvDialog = TTHotSplashAdvDialog(activity, onShow = { container -\u003e\n            EasyAdv.splashConfig()\n                .setCodeId(codeId)\n                .setActivity(activity)\n                .setWidth(activity.getScreenWidth())\n                .setHeight(activity.getScreenHeight())\n                .setContainer(container)\n                .setSplashAdvListener(onError = { _, _ -\u003e\n                    ttHotSplashAdvDialog?.dismiss()\n                }, onAdClicked = { _, _ -\u003e\n                    ttHotSplashAdvDialog?.dismiss()\n                }, onAdSkip = {\n                    ttHotSplashAdvDialog?.dismiss()\n                }, onAdTimeOver = {\n                    ttHotSplashAdvDialog?.dismiss()\n                })\n                .showSplashAdv()\n        }, onDismiss = {})\n        ttHotSplashAdvDialog?.show()\n    }\n}\n```\n\n### 激励广告说明\n\n广告流程大体就跟上面说的差不多，其他广告也一样，激励广告在显示时可能需要先获取接口返回的一些参数 id，在调用的时候传给\n广告sdk 。所以激励广告多了一个拦截器逻辑用来处理这类情况。\n\n```kotlin\nEasyAdv.rewardVideoConfig()\n    .setCodeId(\"KFC_V_WO_50\")\n    .setXXX()\n    ...\n    .addInterceptor(object : AdvInterceptor() {\n        override fun getTag(): String = \"RewardInterceptor\"\n\n        override fun process(map: HashMap\u003cString, String\u003e?, callback: AdvInterceptCallback) {\n            super.process(map, callback)\n            //比如一顿操作后获取到各种参数，然后把他设置到 map 里面即可\n            map?.put(MediationConstant.CUSTOM_DATA_KEY_GROMORE_EXTRA, \"KFC_V_WO_50\")\n            map?.put(MediationConstant.ADN_PANGLE, \"KFC_V_WO_50\")\n            map?.put(MediationConstant.ADN_KS, \"KFC_V_WO_50\")\n            map?.put(MediationConstant.ADN_GDT, \"KFC_V_WO_50\")\n            callback.onNext(map)\n        }\n    })\n```\n\n喜欢的可以点个星，有负责的场景可以提出意见，我会进行完善。\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespoirx%2Feasyadvapp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fespoirx%2Feasyadvapp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fespoirx%2Feasyadvapp/lists"}