前言
本文档详细介绍如何从零开始构建一个组件化的android手游sdk。整个项目采用组件化架构,将sdk的各个功能模块拆分独立开发,最终组合成一个完整的手游sdk。
效果图
单独模块运行

正式包环境运行

第一章 项目整体架构
1.1 架构一览

先来看一下我们项目的整体结构:
zujianmodule (根项目) ├── app # 游戏主入口模块 ├── app-base # sdk核心基础模块 ├── app-login # 登录模块 ├── app-register # 注册模块 ├── app-center # 个人中心模块 ├── app-changepassword # 修改密码模块 ├── app-update # 强制更新模块 ├── lib-util # 工具类库 ├── lib-data # 数据层库 ├── lib-logging # 日志库 ├── lib-permissions # 权限库 └── lib-imgloader # 图片加载库
模块分类:
- app模块:业务功能模块(登录、注册、个人中心等)
- lib模块:公共基础库(供所有模块复用)
1.2 模块依赖关系
app (主模块) └── 依赖所有 app-* 模块 app-base (核心基础) ├── 依赖 lib-util └── 提供:sdkcore、sdkcoreimpl、modulemediator、baseactivity、回调接口 app-login (登录) ├── 依赖 app-base └── 提供:loginactivity app-register (注册) ├── 依赖 app-base └── 提供:registeractivity app-center (个人中心) ├── 依赖 app-base └── 提供:centeractivity app-changepassword (修改密码) ├── 依赖 app-base └── 提供:changepasswordactivity app-update (强制更新) ├── 依赖 app-base └── 提供:updateactivity
第二章 核心技术点详解
2.1 为什么要组件化?
传统sdk开发方式:
- 所有代码写在一个模块里
- 代码耦合严重,难以维护
- 功能扩展困难
- 多人协作困难
组件化优势:
- 模块解耦:每个功能独立模块,职责单一
- 独立运行:开发阶段每个模块可独立运行测试
- 按需加载:发布时可按需求组合
- 团队协作:不同模块可分配给不同人开发
2.2 反射式资源加载(核心黑科技)
这是本项目的核心创新点!传统方式下,每个模块的activity都需要在主项目的androidmanifest中注册,否则找不到。但我们使用反射技术实现了自动发现!
testresourceutil 工具类:
// 反射获取布局资源
public static int getlayoutid(context context, string resname) {
return context.getresources().getidentifier(resname, "layout", context.getpackagename());
}
// 反射获取字符串资源
public static int getstringid(context context, string resname) {
return context.getresources().getidentifier(resname, "string", context.getpackagename());
}
// 反射获取drawable资源
public static int getdrawableid(context context, string resname) {
return context.getresources().getidentifier(resname, "drawable", context.getpackagename());
}
// 反射获取id
public static int getid(context context, string resname) {
return context.getresources().getidentifier(resname, "id", context.getpackagename());
}
在baseactivity中使用:
public abstract class baseactivity extends activity {
// 通过布局名称动态加载布局
public void setcontentview(string layoutid) {
// 传入 "activity_login" 而不是 r.layout.activity_login
super.setcontentview(testresourceutil.getlayoutid(mcontext, layoutid));
}
// 通过控件id名称查找控件
public view findviewbyid(string viewid) {
// 传入 "btn_login" 而不是 r.id.btn_login
return super.findviewbyid(testresourceutil.getid(mcontext, viewid));
}
}
activity中使用:
public class loginactivity extends baseactivity {
@override
protected void loadviewlayout() {
// 直接写字符串,框架自动找资源!
setcontentview("activity_login");
}
@override
protected void findviewbyid() {
// 控件也是字符串形式
button btnlogin = findviewbyid("btn_login");
}
}
💡 好处:再也不用担心模块间资源id冲突问题了!每个模块可以有自己的
activity_login.xml!
2.3 模块初始化机制
每个功能模块都需要一个app类实现appinitial接口,这样主项目就能在运行时自动初始化所有模块:
appinitial接口:
public interface appinitial {
void init(application app);
}
登录模块的app类:
public class app implements modulemediator.appinitial {
@override
public void init(application app) {
// 这里可以初始化登录模块特有的东西
// 比如配置第三方登录sdk
}
}
modulemediator统一初始化:
public class modulemediator {
// 每个模块的app类全限定名
private static final string app_login_class = "com.github.jeffery.login.app";
private static final string app_center_class = "com.github.jeffery.center.app";
private static final string app_register_class = "com.github.jeffery.register.app";
private static final string app_changepassword_class = "com.github.jeffery.changepassword.app";
private static final string app_update_class = "com.github.jeffery.update.app";
// 一次性初始化所有模块
public static void init(application app) {
string[] appclasses = {
app_login_class,
app_center_class,
app_register_class,
app_changepassword_class,
app_update_class
};
for (string claname : appclasses) {
try {
class<?> clz = class.forname(claname);
appinitial obj = (appinitial) clz.newinstance();
obj.init(app);
} catch (exception e) {
e.printstacktrace();
}
}
}
}
2.4 路由跳转机制
类似于arouter,但更轻量级!使用字符串常量来标识目标页面:
public class modulemediator {
// 页面路由常量
public static final string activity_login_class = "com.github.jeffery.login.loginactivity";
public static final string activity_center_class = "com.github.jeffery.center.centeractivity";
public static final string activity_register_class = "com.github.jeffery.register.registeractivity";
public static final string activity_changepassword_class = "com.github.jeffery.changepassword.changepasswordactivity";
public static final string activity_update_class = "com.github.jeffery.update.updateactivity";
// 单例模式
private static volatile modulemediator instance;
public static modulemediator getinstance() {
if (instance == null) {
synchronized (modulemediator.class) {
if (instance == null) {
instance = new modulemediator();
}
}
}
return instance;
}
// 跳转activity
public void startactivity(activity activity, string classname) {
startactivity(activity, classname, null);
}
public void startactivity(activity activity, string classname, bundle bundle) {
try {
class<?> clazz = class.forname(classname);
intent intent = new intent(activity, clazz);
if (bundle != null) {
intent.putextras(bundle);
}
activity.startactivity(intent);
} catch (classnotfoundexception e) {
e.printstacktrace();
toast.maketext(activity, "找不到" + e.getmessage(), toast.length_short).show();
}
}
}
使用示例:
// 跳转到登录页
modulemediator.getinstance().startactivity(this,
modulemediator.activity_login_class);
// 带参数跳转到注册页
bundle params = new bundle();
params.putstring("from", "login");
modulemediator.getinstance().startactivity(this,
modulemediator.activity_register_class, params);
第三章 核心功能实现
3.1 sdk核心类设计
sdkcore抽象类(定义规范):
public abstract class sdkcore {
// 初始化
public abstract void init(context context);
// 登录
public abstract void login(logincallback callback);
// 支付
public abstract void pay(payparams params, paycallback callback);
// 登出
public abstract void logout(logoutcallback callback);
// 退出游戏
public abstract void exitgame(exitcallback callback);
// 数据上报
public abstract void reportdata(string eventid, object params);
// 生命周期
public abstract void oncreate();
public abstract void onstart();
public abstract void onresume();
public abstract void onpause();
public abstract void onstop();
public abstract void ondestroy();
}
sdkcoreimpl实现类(单例模式):
public class sdkcoreimpl extends sdkcore {
private static volatile sdkcoreimpl instance;
private context mcontext;
private boolean isinitialized = false;
private string currentuserid;
private string currentusername;
private string currenttoken;
private sdkcoreimpl() {
// 私有构造函数
}
public static sdkcoreimpl getinstance() {
if (instance == null) {
synchronized (sdkcoreimpl.class) {
if (instance == null) {
instance = new sdkcoreimpl();
}
}
}
return instance;
}
@override
public void init(context context) {
this.mcontext = context.getapplicationcontext();
this.isinitialized = true;
}
// ... 其他方法实现
}
3.2 回调接口设计
所有回调继承自基础接口:
// 基础回调
public interface sdkcallback {
void onsuccess(object data);
void onfailure(int code, string msg);
}
// 登录回调
public interface logincallback extends sdkcallback {
void onloginsuccess(string userid, string username, string token);
void onlogincancel();
}
// 支付回调
public interface paycallback extends sdkcallback {
void onpaysuccess(string orderid, string productid);
void onpaycancel();
void onpaypending(string msg);
}
// 登出回调
public interface logoutcallback extends sdkcallback {
void onlogoutsuccess();
}
// 退出游戏回调
public interface exitcallback extends sdkcallback {
void onconfirmexit();
void oncancelexit();
}
3.3 支付参数类
public class payparams {
private string productid; // 商品id
private string productname; // 商品名称
private int price; // 价格(分)
private string currency; // 货币类型
private string orderid; // 订单号
private string roleid; // 角色id
private string rolename; // 角色名称
private string serverid; // 服务器id
private string servername; // 服务器名称
private string extdata; // 扩展数据
// getter and setter...
}
第四章 模块创建步骤
4.1 创建新模块
假设我们要创建一个"礼包"模块 app-gift:
1. 在settings.gradle中添加:
include ':app-gift'
2. 创建build.gradle:
plugins {
id 'com.android.library'
}
android {
compilesdk buildversion.compilesdk
defaultconfig {
minsdk buildversion.minsdk
targetsdk buildversion.targetsdk
// 开发阶段可以独立运行
if (!isrelease) {
applicationid 'com.github.jeffery.gift'
versioncode 1
versionname '1.0'
}
}
}
// 资源前缀,避免资源名冲突
android.resourceprefix 'gift_'
dependencies {
// 依赖基础模块
api project(':app-base')
}
3. 创建包结构和类:
app-gift/src/main/java/com/github/jeffery/gift/ ├── app.java # 模块初始化类 ├── giftactivity.java # 礼包activity └── ...
4. 创建app类:
package com.github.jeffery.gift;
import android.app.application;
import com.github.jeffery.utils.modulemediator;
public class app implements modulemediator.appinitial {
@override
public void init(application app) {
// 初始化礼包模块
}
}
5. 在modulemediator中添加路由:
public static final string activity_gift_class = "com.github.jeffery.gift.giftactivity";
4.2 资源文件规范
为避免资源冲突,每个模块的资源都要有模块前缀:
| 模块 | 布局前缀 | 字符串前缀 | 颜色前缀 | 尺寸前缀 |
|---|---|---|---|---|
| app-login | login_ | login_ | login_ | login_ |
| app-register | register_ | register_ | register_ | register_ |
| app-center | center_ | center_ | center_ | center_ |
| app-gift | gift_ | gift_ | gift_ | gift_ |
示例:
activity_login.xml→login_activity.xmlbtn_login→login_btn_submit@string/login_hint→@string/login_hint
第五章 集成到游戏项目
5.1 主项目build.gradle配置
dependencies {
implementation project(':app-base')
implementation project(':app-login')
implementation project(':app-register')
implementation project(':app-center')
implementation project(':app-changepassword')
implementation project(':app-update')
}
5.2 application初始化
public class gameapplication extends application {
@override
public void oncreate() {
super.oncreate();
// 1. 初始化所有sdk模块
modulemediator.init(this);
// 2. 初始化sdk核心
sdkcoreimpl.getinstance().init(this);
}
}
5.3 生命周期集成
public class mainactivity extends appcompatactivity {
@override
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
sdkcoreimpl.getinstance().oncreate();
}
@override
protected void onstart() {
super.onstart();
sdkcoreimpl.getinstance().onstart();
}
@override
protected void onresume() {
super.onresume();
sdkcoreimpl.getinstance().onresume();
}
@override
protected void onpause() {
super.onpause();
sdkcoreimpl.getinstance().onpause();
}
@override
protected void onstop() {
super.onstop();
sdkcoreimpl.getinstance().onstop();
}
@override
protected void ondestroy() {
super.ondestroy();
sdkcoreimpl.getinstance().ondestroy();
}
}
5.4 常用api调用
登录:
sdkcoreimpl.getinstance().login(new logincallback() {
@override
public void onloginsuccess(string userid, string username, string token) {
log.d("login", "登录成功!userid=" + userid);
}
@override
public void onlogincancel() {
log.d("login", "用户取消登录");
}
@override
public void onsuccess(object data) {}
@override
public void onfailure(int code, string msg) {
log.e("login", "登录失败:" + msg);
}
});
支付:
payparams params = new payparams();
params.setproductid("com.game.gems_100");
params.setproductname("100钻石");
params.setprice(100);
sdkcoreimpl.getinstance().pay(params, new paycallback() {
@override
public void onpaysuccess(string orderid, string productid) {
log.d("pay", "支付成功!");
}
// ...
});
数据上报:
// 简单事件
sdkcoreimpl.getinstance().reportdata("level_start", null);
// 带参数事件
map<string, object> params = new hashmap<>();
params.put("level_id", 1);
sdkcoreimpl.getinstance().reportdata("level_complete", params);
第六章 开发与发布模式
6.1 开发模式(isrelease = false)
// env.gradle isrelease = false
特点:
- 每个模块都有独立的applicationid
- 可以独立安装运行调试
- 便于团队成员独立开发
6.2 发布模式(isrelease = true)
// env.gradle isrelease = true
特点:
- 所有模块合并为一个sdk
- 只生成一个applicationid
- 减少包体积
第七章 常见问题解答
q1: 如何添加新功能模块?
- 创建新模块(参考第四章)
- 在modulemediator中添加路由常量
- 在settings.gradle中include
- 在主模块build.gradle中添加依赖
q2: 模块间如何通信?
通过modulemediator单例进行通信,也可以直接使用sdkcoreimpl的实例方法。
q3: 资源冲突怎么办?
每个模块使用独立的资源前缀(通过android.resourceprefix配置),加上反射式加载,不会有id冲突。
q4: 如何调试单个模块?
在env.gradle中设置isrelease = false,该模块就可以独立安装运行。
附录:目录结构参考
项目根目录/ ├── app.gradle # app模块配置 ├── build.gradle # 根项目配置 ├── env.gradle # 环境变量配置 ├── settings.gradle # 模块列表 ├── app/ # 游戏主模块 ├── app-base/ # sdk基础模块 │ └── src/main/java/com/github/jeffery/utils/ │ ├── sdkcore.java │ ├── sdkcoreimpl.java │ ├── modulemediator.java │ ├── baseactivity.java │ ├── logincallback.java │ ├── paycallback.java │ └── ... ├── app-login/ # 登录模块 ├── app-register/ # 注册模块 ├── app-center/ # 个人中心模块 ├── app-changepassword/ # 修改密码模块 ├── app-update/ # 强制更新模块 ├── lib-util/ # 工具库 ├── lib-data/ # 数据库 ├── lib-logging/ # 日志库 ├── lib-permissions/ # 权限库 └── lib-imgloader/ # 图片加载库
总结
本项目通过以下技术实现了一个轻量级的android手游sdk组件化方案:
- 反射式资源加载 - 解决资源id冲突问题
- modulemediator - 统一模块初始化和页面路由
- appinitial接口 - 模块热插拔
- 单例模式 - 核心类全局唯一实例
- 回调接口 - 异步通信标准化
整个方案不依赖任何第三方路由框架,代码量少,易于理解和维护,非常适合中小型手游sdk开发。
到此这篇关于android手游sdk组件化开发南的文章就介绍到这了,更多相关android手游sdk组件化内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论