feat: 添加广告激励下载功能
- 优化useAd Hook支持奖励和关闭回调 - 在预览页面添加看广告下载按钮 - 实现下载图片到本地相册功能 - 添加完整的中文注释和业务逻辑处理
This commit is contained in:
parent
82e01276be
commit
e7c1743bd5
|
|
@ -1,37 +1,85 @@
|
|||
import { createPlatformFactory, RewardedVideoAd, RewardedVideoCloseCb, RewardedVideoErrorCb } from "../platforms";
|
||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||
|
||||
// 广告奖励回调函数类型
|
||||
type AdRewardCallback = () => void;
|
||||
|
||||
// 广告 Hook 返回接口
|
||||
interface UseAdReturn {
|
||||
showAd: () => void;
|
||||
loadAd: () => void;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export function useAd(): UseAdReturn {
|
||||
// 广告 Hook 配置选项
|
||||
interface UseAdOptions {
|
||||
onReward?: AdRewardCallback; // 观看完整广告后的奖励回调
|
||||
onClose?: (isEnded: boolean) => void; // 广告关闭回调,传入是否完整观看
|
||||
}
|
||||
|
||||
export function useAd(options?: UseAdOptions): UseAdReturn {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const adRef = useRef<RewardedVideoAd | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 创建平台广告实例
|
||||
const factory = createPlatformFactory()
|
||||
adRef.current = factory.createRewardedVideoAd({
|
||||
adUnitId: 'gncb4kr2b6kwp0uacr'
|
||||
});
|
||||
const ad = adRef.current!;
|
||||
|
||||
// 广告关闭回调处理
|
||||
const onClose: RewardedVideoCloseCb = (res) => {
|
||||
console.log('广告关闭:', res);
|
||||
setLoading(false);
|
||||
|
||||
// 判断用户是否完成播放
|
||||
const isEnded = Boolean(res?.isEnded);
|
||||
|
||||
if (isEnded) {
|
||||
// 播放完成的业务逻辑
|
||||
console.log('用户观看完整广告,给予奖励');
|
||||
|
||||
// 执行奖励回调
|
||||
options?.onReward?.();
|
||||
|
||||
// 可以在这里处理以下业务:
|
||||
// 1. 发放奖励(积分、道具等)
|
||||
// 2. 解锁功能或内容
|
||||
// 3. 统计完成观看数据
|
||||
// 4. 触发下一步操作
|
||||
|
||||
} else {
|
||||
// 未完成播放的处理
|
||||
console.log('用户未完整观看广告');
|
||||
|
||||
// 可以处理以下场景:
|
||||
// 1. 提示用户观看完整广告才能获得奖励
|
||||
// 2. 记录未完成播放的统计
|
||||
// 3. 可能的重试提示
|
||||
}
|
||||
|
||||
// 执行关闭回调,传入是否完整观看
|
||||
options?.onClose?.(isEnded);
|
||||
}
|
||||
// 广告加载错误回调处理
|
||||
const onError: RewardedVideoErrorCb = (res) => {
|
||||
console.error('广告错误:', res);
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
// 广告加载成功回调处理
|
||||
const onLoad = () => {
|
||||
console.log(`广告加载`)
|
||||
console.log('广告加载成功');
|
||||
setLoading(false);
|
||||
}
|
||||
// 绑定广告事件监听
|
||||
ad.onLoad(onLoad);
|
||||
ad.onClose(onClose);
|
||||
ad.onError(onError);
|
||||
|
||||
// 清理函数:组件卸载时移除事件监听和销毁广告实例
|
||||
return () => {
|
||||
if (adRef.current) {
|
||||
adRef.current.offClose(onClose)
|
||||
|
|
@ -40,8 +88,9 @@ export function useAd(): UseAdReturn {
|
|||
adRef.current.destroy();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
}, [options]);
|
||||
|
||||
// 显示广告方法
|
||||
const showAd = useCallback(() => {
|
||||
if (adRef.current) {
|
||||
setLoading(true);
|
||||
|
|
@ -49,6 +98,7 @@ export function useAd(): UseAdReturn {
|
|||
}
|
||||
}, []);
|
||||
|
||||
// 加载广告方法
|
||||
const loadAd = useCallback(() => {
|
||||
if (adRef.current) {
|
||||
setLoading(true);
|
||||
|
|
|
|||
|
|
@ -405,3 +405,73 @@
|
|||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 下载区域样式 */
|
||||
.download-section {
|
||||
position: absolute;
|
||||
bottom: 60rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
padding: 0 40rpx;
|
||||
box-sizing: border-box;
|
||||
z-index: 1001;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 下载按钮样式 */
|
||||
.download-btn {
|
||||
background: linear-gradient(135deg, #ff6b9d, #ff9a56);
|
||||
border: none;
|
||||
border-radius: 50rpx;
|
||||
padding: 20rpx 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 8rpx 25rpx rgba(255, 107, 157, 0.4);
|
||||
min-width: 320rpx;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.download-btn::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.3),
|
||||
transparent
|
||||
);
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.download-btn:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.download-btn:active {
|
||||
transform: translateY(2rpx);
|
||||
box-shadow: 0 4rpx 15rpx rgba(255, 107, 157, 0.3);
|
||||
}
|
||||
|
||||
.download-btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* 下载提示文字 */
|
||||
.download-tip {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
margin-top: 20rpx;
|
||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
line-height: 1.4;
|
||||
display: block;
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import { View, Text, Button, Image, Swiper, SwiperItem } from '@tarojs/components'
|
||||
import { useLoad } from '@tarojs/taro'
|
||||
import { useLoad, saveImageToPhotosAlbum, downloadFile, showToast } from '@tarojs/taro'
|
||||
import { useState } from 'react'
|
||||
import './index.css'
|
||||
import { useSdk } from '../../hooks/index'
|
||||
import { useAd } from '../../hooks/useAd'
|
||||
|
||||
type PageStep = 'upload' | 'loading' | 'result' | 'error'
|
||||
|
||||
|
|
@ -20,6 +21,19 @@ export default function Index() {
|
|||
error: null
|
||||
})
|
||||
|
||||
// 广告激励下载功能
|
||||
const { showAd, loading: adLoading } = useAd({
|
||||
onReward: () => {
|
||||
// 观看完整广告后下载图片
|
||||
handleDownloadImages()
|
||||
},
|
||||
onClose: (isEnded) => {
|
||||
if (!isEnded) {
|
||||
console.log('需要观看完整广告才能下载')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
useLoad(() => {
|
||||
return () => { }
|
||||
})
|
||||
|
|
@ -43,6 +57,43 @@ export default function Index() {
|
|||
setState({ step: 'upload', images: [], error: null })
|
||||
}
|
||||
|
||||
// 下载图片到本地相册
|
||||
const handleDownloadImages = async () => {
|
||||
try {
|
||||
showToast({ title: '开始下载...', icon: 'loading' })
|
||||
|
||||
for (const imageUrl of state.images) {
|
||||
// 先下载图片到临时文件
|
||||
const downloadRes = await downloadFile({ url: imageUrl })
|
||||
|
||||
// 保存到相册
|
||||
await saveImageToPhotosAlbum({ filePath: downloadRes.tempFilePath })
|
||||
}
|
||||
|
||||
showToast({
|
||||
title: `成功下载${state.images.length}张图片`,
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('下载失败:', error)
|
||||
showToast({
|
||||
title: '下载失败,请重试',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 触发看广告下载
|
||||
const handleWatchAdToDownload = () => {
|
||||
if (adLoading) {
|
||||
showToast({ title: '广告加载中...', icon: 'loading' })
|
||||
return
|
||||
}
|
||||
showAd()
|
||||
}
|
||||
|
||||
// 1. 传图片环节
|
||||
const renderUploadStep = () => (
|
||||
<View className="button-container">
|
||||
|
|
@ -84,6 +135,18 @@ export default function Index() {
|
|||
</SwiperItem>
|
||||
))}
|
||||
</Swiper>
|
||||
|
||||
{/* 下载按钮区域 */}
|
||||
<View className="download-section">
|
||||
<Button
|
||||
className="download-btn"
|
||||
onClick={handleWatchAdToDownload}
|
||||
disabled={adLoading}
|
||||
>
|
||||
{adLoading ? '广告加载中...' : '📱 看广告下载到相册'}
|
||||
</Button>
|
||||
<Text className="download-tip">观看完整广告即可免费下载所有图片</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue