一、系统架构设计:模块化与跨平台
1.1 技术栈选型
- 前端:Flutter(跨平台支持iOS/Android)+ Video Player插件(支持短剧播放)
- 后端:Spring Boot(Java) + MyBatis Plus(ORM)
- 数据库:MySQL(用户/广告数据) + Redis(金币缓存)
- 广告联盟:穿山甲(今日头条)、优量汇(腾讯)、Google AdMob
- 部署:Docker(容器化) + Nginx(反向代理) + 阿里云ECS(服务器)
1.2 系统分层设计
├── 前端(Flutter) | |
│ ├── 用户模块(登录/注册) | |
│ ├── 短剧模块(播放/缓存) | |
│ ├── 广告模块(激励视频/插屏广告) | |
│ └── 金币模块(任务/兑换) | |
├── 后端(Spring Boot) | |
│ ├── 用户服务(JWT鉴权) | |
│ ├── 广告服务(广告联盟SDK对接) | |
│ ├── 金币服务(事务控制) | |
│ └── 内容服务(短剧版权管理) | |
└── 数据库 | |
├── MySQL(用户表、广告记录表、金币流水表) | |
└── Redis(用户金币缓存、广告位缓存) |
二、核心功能实现:看广告赚金币全流程
2.1 用户系统(JWT鉴权)
java
// Spring Boot JWT配置类 | |
@Configuration | |
public class JwtConfig { | |
@Bean | |
public JwtParser jwtParser() { | |
return Jwts.parser().setSigningKey(Keys.hmacShaKeyFor("your-secret-key".getBytes())); | |
} | |
} | |
// 登录接口 | |
@PostMapping("/login") | |
public ResponseEntity<?> login(@RequestBody User user) { | |
String token = Jwts.builder() | |
.setSubject(user.getUsername()) | |
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) | |
.signWith(SignatureAlgorithm.HS512, "your-secret-key") | |
.compact(); | |
return ResponseEntity.ok(new JwtResponse(token)); | |
} |
2.2 广告模块(穿山甲SDK集成)
java
// Android端激励视频广告加载 | |
private void loadRewardVideoAd() { | |
RewardVideoAd rewardVideoAd = new RewardVideoAd(this, "your_ad_unit_id"); | |
rewardVideoAd.setAdListener(new RewardVideoAdListener() { | |
@Override | |
public void onAdShow() {} | |
@Override | |
public void onAdClose() { | |
// 用户关闭广告后发放金币 | |
addCoins(userId, 10); // 奖励10金币 | |
} | |
}); | |
rewardVideoAd.loadAd(); | |
} |
2.3 金币系统(事务控制)
sql
-- MySQL金币流水表 | |
CREATE TABLE coin_transaction ( | |
id BIGINT PRIMARY KEY AUTO_INCREMENT, | |
user_id BIGINT NOT NULL, | |
amount INT NOT NULL, | |
type VARCHAR(20) NOT NULL, -- 'AD_REWARD', 'EXCHANGE' | |
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | |
); | |
-- Spring Boot事务方法 | |
@Transactional | |
public void addCoins(Long userId, int amount) { | |
// 更新用户金币(先查缓存,失败则查数据库) | |
Integer coins = redisTemplate.opsForValue().get("user:coins:" + userId); | |
if (coins == null) { | |
coins = userMapper.selectCoinsByUserId(userId); | |
redisTemplate.opsForValue().set("user:coins:" + userId, coins); | |
} | |
redisTemplate.opsForValue().set("user:coins:" + userId, coins + amount); | |
// 记录流水 | |
CoinTransaction transaction = new CoinTransaction(); | |
transaction.setUserId(userId); | |
transaction.setAmount(amount); | |
transaction.setType("AD_REWARD"); | |
coinTransactionMapper.insert(transaction); | |
} |
2.4 短剧播放模块(Flutter实现)
dart
// Flutter视频播放页面 | |
class VideoPlayerPage extends StatefulWidget { | |
final String videoUrl; | |
VideoPlayerPage({required this.videoUrl}); | |
@override | |
_VideoPlayerPageState createState() => _VideoPlayerPageState(); | |
} | |
class _VideoPlayerPageState extends State<VideoPlayerPage> { | |
late VideoPlayerController _controller; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = VideoPlayerController.network(widget.videoUrl) | |
..initialize().then((_) { | |
setState(() {}); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar(title: Text('短剧播放')), | |
body: Center( | |
child: _controller.value.isInitialized | |
? AspectRatio( | |
aspectRatio: _controller.value.aspectRatio, | |
child: VideoPlayer(_controller), | |
) | |
: CircularProgressIndicator(), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: () { | |
setState(() { | |
_controller.value.isPlaying | |
? _controller.pause() | |
: _controller.play(); | |
}); | |
}, | |
child: Icon( | |
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow, | |
), | |
), | |
); | |
} | |
} |
三、广告联盟对接:从注册到收益
3.1 穿山甲(今日头条)对接流程
- 注册账号:访问穿山甲官网,完成企业认证。
- 创建应用:在后台填写APP名称、包名、签名等信息。
- 获取SDK:下载Android/iOS SDK,集成到项目中。
- 配置广告位:创建激励视频广告位,记录
ad_unit_id
。 - 测试广告:使用测试ID验证广告加载与展示。
3.2 广告事件监听(Android端)
java
// 广告加载成功 | |
@Override | |
public void onRewardedVideoAdLoaded() { | |
Log.d("Ad", "激励视频加载成功"); | |
} | |
// 广告奖励发放 | |
@Override | |
public void onRewardedVideoAdReward(Map<String, Object> extraData) { | |
String userId = extraData.get("userId").toString(); | |
int coins = Integer.parseInt(extraData.get("coins").toString()); | |
// 调用后端接口发放金币 | |
addCoins(userId, coins); | |
} |
3.3 广告收益结算
- 结算规则:穿山甲默认T+1结算,需满足100元起提。
- 数据监控:通过广告联盟后台查看eCPM、填充率、点击率等指标。
四、上线部署:从源码到应用市场
4.1 源码交付标准
- 前端:Flutter工程目录完整,
pubspec.yaml
依赖清晰。 - 后端:Spring Boot工程包含
pom.xml
、配置文件(需脱敏)。 - 数据库:提供SQL初始化脚本,包含测试数据。
- 文档:接口文档(Swagger)、部署手册、常见问题FAQ。
4.2 服务器部署(Docker)
dockerfile
# Dockerfile(Spring Boot) | |
FROM openjdk:17-alpine | |
VOLUME /tmp | |
COPY target/*.jar app.jar | |
ENTRYPOINT ["java","-jar","/app.jar"] |
bash
# 部署命令 | |
docker build -t short-drama-app . | |
docker run -d -p 8080:8080 --name short-drama short-drama-app |
4.3 应用市场上架
- iOS:提交至App Store,需准备企业账号、隐私政策URL。
- Android:上传至应用宝、华为市场,需提供软著证书、测试报告。
五、防作弊与用户体验优化
5.1 防作弊策略
- 设备检测:禁止虚拟机、模拟器运行(通过设备指纹识别)。
- IP限制:同一IP每日奖励上限(如100金币)。
- 行为分析:检测异常点击(如短时间内多次观看广告)。
5.2 用户体验优化
- 广告频率:每观看3集短剧展示一次广告(避免过度干扰)。
- 缓存机制:预加载短剧内容,减少播放等待时间。
- 金币提醒:用户获得金币后弹出Toast提示,增强成就感。
六、总结与扩展方向
6.1 核心价值
- 用户:通过碎片化时间赚取收益,降低短剧观看门槛。
- 平台:广告联盟分成+用户付费(如去广告会员)。
- 内容方:通过广告曝光量获得分成。
6.2 扩展方向
- 社交功能:增加用户互动(如评论、分享)。
- AI推荐:基于用户观看习惯推荐短剧。
- 区块链:金币上链,支持NFT兑换(需合规)。
通过本文攻略,开发者可快速搭建一套完整的短剧看广告APP系统,实现从源码交付到广告联盟对接的全流程闭环。实际开发中需重点关注广告联盟政策合规性,并持续优化用户体验以提升留存率。