网易首页 > 网易号 > 正文 申请入驻

零基础开启元宇宙|如何快速创建虚拟形象

0
分享至

元宇宙(Metaverse),是人类运用数字技术构建的,由现实世界映射或超越现实世界,可与现实世界交互的虚拟世界,具备新型社会体系的数字生活空间。

可见元宇宙第一步是创建专属虚拟形象,但创建3D虚拟形象需要3D基础知识。对于大部分android开发者(包括我本人)来说没有这方面的积累。难道因此我们就难以进入元宇宙的世界吗?不,今天我们借助即构平台提供的Avatar SDK,只要有Android基础即可进入最火的元宇宙世界!先看效果:

上面gif被压缩的比较狠,这里放一张截图:

1 免费注册即构开发者

前往即构控制台网站,注册开发者账户。注册成功后,创建项目:

控制台中可以得到AppID和AppSign两个数据,这两个数据是重要凭证,后面会用到。

由于我们用到了即构的Avatar功能,但目前官方没有提供线上自动开启方式,需要主动找客服申请(当然,这是免费的),只需提供自己项目的包名,即可开通Avatar权限。打开右下角有“联系我们”,点击即可跟客服申请免费开通权限。

注意,如果不向客服申请Avatar权限,调用AvatarSDK会失败!

2 准备开发环境

前往即构官方元宇宙开发SDK网站下载SDK,得到如下文件列表:

接下来过程如下:

  1. 打开SDK目录,将里面的ZegoAvatar.aar拷贝至app/libs目录下。
  2. 添加SDK引用。打开app/build.gradle文件,在dependencies节点引入 libs下所有的jar和aar:

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', "*.aar"]) //通配引入
//其他略
}

3、设置权限。根据实际应用需要,设置应用所需权限。进入app/src/main/AndroidManifest.xml 文件,添加权限。


android:glEsVersion="0x00020000"
android:required="true" />

因为在一些比较重要的权限上要求必须申请动态权限,不能只通过 文件申请静态权限。具体动态请求权限代码可看附件源码。
Android 6.0
AndroidMainfest.xml
因为Android 6.0在一些比较重要的权限上要求必须申请动态权限,不能只通过 AndroidMainfest.xml文件申请静态权限。具体动态请求权限代码可看附件源码。

3 导入资源

上一小节下载的zip文件中,有个assets目录。里面包含了Avatar形象相关资源,如:衣服、眉毛、鞋子等。这是即构官方免费提供的资源,可以满足一般性需求了。当然了,如果想要自己定制资源也是可以的。assets文件内容如下:

资源名称

说明

AIModel.bundle

Avatar 的 AI 模型资源。当使用表情随动、声音随动、AI 捏脸等能力时,必须先将该资源的绝对路径设置给 Avatar SDK。

base.bundle

美术资源,包含基础 3D 人物模型资源、资源映射表、人物模型默认外形等。

Packages

美妆、挂件、装饰等资源。 每个资源 200 KB ~ 1 MB 不等,跟资源复杂度相关。

注意:由于资源文件很大,上面下载的美术资源只包含少量必须资源。如果需要全部资源,可以去官网找客服索要

上面的文件需要存放到Android本地SDCard上,这里有2个方案可供参考:

  • 方案一: 将资源先放入到app/src/assets目录内,然后在app启动时,自动将assets的内容拷贝到SDcard中。
  • 方案二: 将资源放入到服务器端,运行时自动从服务器端下载。

为了简单起见,我们这里采用方案一。参考代码如下, 详细代码可以看附件:

AssetsFileTransfer.copyAssetsDir2Phone(this.getApplication(),

"AIModel.bundle", "assets");

AssetsFileTransfer.copyAssetsDir2Phone(this.getApplication(),

"base.bundle", "assets");

AssetsFileTransfer.copyAssetsDir2Phone(this.getApplication(),

"Packages", "assets");

4 创建虚拟形象

创建虚拟形象本质上来说就是调用即构的Avatar SDK,其大致流程如下:

接下来我们逐步实现上面流程。

需要注意的是,上面示意图中采用的是AvatarView,可以非常方便的直接展示Avatar形象,但是不方便后期将画面通过RTC实时传递, 因此,我们后面的具体实现通过TextureView替代AvatarView。

4.1 申请权鉴

这里再次强调一下,一定要打开点击右下角有“联系我们”,向客服申请免费开通Avatar权限。否则无法使用Avatar SDK。

申请权鉴代码如下:

public class KeyCenter {

// 控制台地址: https://console.zego.im/dashboard

public static long APP_ID = 这里值可以在控制台查询,参考第一节; //这里填写APPID

public static String APP_SIGN = 这里值可以在控制台查询,参考第一节;

// 鉴权服务器的地址

public final static String BACKEND_API_URL = "https://aieffects-api.zego.im?Action=DescribeAvatarLicense";

public static String avatarLicense = null;

public static String getURL(String authInfo) {

Uri.Builder builder = Uri.parse(BACKEND_API_URL).buildUpon();

builder.appendQueryParameter("AppId", String.valueOf(APP_ID));

builder.appendQueryParameter("AuthInfo", authInfo);

return builder.build().toString();

public interface IGetLicenseCallback {

void onGetLicense(int code, String message, ZegoLicense license);

* 在线拉取 license

* @param context

* @param callback

public static void getLicense(Context context, final IGetLicenseCallback callback) {

requestLicense(ZegoAvatarService.getAuthInfo(APP_SIGN, context), callback);

* 获取license

public static void requestLicense(String authInfo, final IGetLicenseCallback callback) {

String url = getURL(authInfo);

HttpRequest.asyncGet(url, ZegoLicense.class, (code, message, responseJsonBean) -> {

if (callback != null) {

callback.onGetLicense(code, message, responseJsonBean);

public class ZegoLicense {

@SerializedName("License")

private String license;

public String getLicense() {

return license;

public void setLicense(String license) {

this.license = license;

在获取Lincense时,只需调用getLicense函数,例如在Activity类中只需如下调用:

KeyCenter.getLicense(this, (code, message, response) -> {

if (code == 0) {

KeyCenter.avatarLicense = response.getLicense();

showLoading("正在初始化...");

avatarMngr = AvatarMngr.getInstance(getApplication());

avatarMngr.setLicense(KeyCenter.avatarLicense, this);

} else {

toast("License 获取失败, code: " + code);

4.2 初始化AvatarService

初始化AvatarService过程比较漫长(可能要几秒),通过开启worker线程后台加载以避免主线程阻塞。因此我们定义一个回调函数,待完成初始化后回调通知:

public interface OnAvatarServiceInitSucced {

void onInitSucced();

public void setLicense(String license, OnAvatarServiceInitSucced listener) {

this.listener = listener;

ZegoAvatarService.addServiceObserver(this);

String aiPath = FileUtils.getPhonePath(mApp, "AIModel.bundle", "assets"); // AI 模型的绝对路径

ZegoServiceConfig config = new ZegoServiceConfig(license, aiPath);

ZegoAvatarService.init(mApp, config);

@Override

public void onStateChange(ZegoAvatarServiceState state) {

if (state == ZegoAvatarServiceState.InitSucceed) {

Log.i("ZegoAvatar", "Init success");

// 要记得及时移除通知

ZegoAvatarService.removeServiceObserver(this);

if (listener != null) listener.onInitSucced();

这里setLicense函数内完成初始化AvatarService,初始化完成后会回调onStateChange函数。但是要注意,在初始化之前必须把资源文件拷贝到本地SDCard,即完成资源导入:

private void initRes(Application app) {

// 先把资源拷贝到SD卡,注意:线上使用时,需要做一下判断,避免多次拷贝。资源也可以做成从网络下载。

if (!FileUtils.checkFile(app, "AIModel.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "AIModel.bundle", "assets");

if (!FileUtils.checkFile(app, "base.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "base.bundle", "assets");

if (!FileUtils.checkFile(app, "human.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "human.bundle", "assets");

if (!FileUtils.checkFile(app, "Packages", "assets"))

FileUtils.copyAssetsDir2Phone(app, "Packages", "assets");

4.3 创建虚拟形象

前面在下载SDK包含了helper目录,这个目录里面有非常重要的两个文件:

其中ZegoCharacterHelper文件是个接口定义类,即虽然是个类,但具体的实现全部在ZegoCharacterHelperImpl中。我们先一睹为快,看看ZegoCharacterHelper包含了哪些可处理的属性:

public class ZegoCharacterHelper {

public static final String MODEL_ID_MALE = "male";

public static final String MODEL_ID_FEMALE = "female";

//****************************** 捏脸维度的 key 值 ******************************/

public static final String FACESHAPE_BROW_SIZE_Y = "faceshape_brow_size_y";// 眉毛厚度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_BROW_SIZE_X = "faceshape_brow_size_x";// 眉毛长度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_BROW_ALL_Y = "faceshape_brow_all_y";// 眉毛高度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_BROW_ALL_ROLL_Z = "faceshape_brow_all_roll_z";// 眉毛旋转, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_EYE_SIZE = "faceshape_eye_size"; // 眼睛大小, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_EYE_SIZE_Y = "faceshape_eye_size_y";

public static final String FACESHAPE_EYE_ROLL_Y = "faceshape_eye_roll_y";// 眼睛高度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_EYE_ROLL_Z = "faceshape_eye_roll_z";// 眼睛旋转, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_EYE_X = "faceshape_eye_x";// 双眼眼距, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_NOSE_ALL_X = "faceshape_nose_all_x";// 鼻子宽度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_NOSE_ALL_Y = "faceshape_nose_all_y";// 鼻子高度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_NOSE_SIZE_Z = "faceshape_nose_size_z";

public static final String FACESHAPE_NOSE_ALL_ROLL_Y = "faceshape_nose_all_roll_y";// 鼻头旋转, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_NOSTRIL_ROLL_Y = "faceshape_nostril_roll_y";// 鼻翼旋转, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_NOSTRIL_X = "faceshape_nostril_x";

public static final String FACESHAPE_MOUTH_ALL_Y = "faceshape_mouth_all_y";// 嘴巴上下, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_LIP_ALL_SIZE_Y = "faceshape_lip_all_size_y";// 嘴唇厚度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_LIPCORNER_Y = "faceshape_lipcorner_y";// 嘴角旋转, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_LIP_UPPER_SIZE_X = "faceshape_lip_upper_size_x"; // 上唇宽度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_LIP_LOWER_SIZE_X = "faceshape_lip_lower_size_x"; // 下唇宽度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_JAW_ALL_SIZE_X = "faceshape_jaw_all_size_x";// 下巴宽度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_JAW_Y = "faceshape_jaw_y";// 下巴高度, 取值范围0.0-1.0,默认值0.5

public static final String FACESHAPE_CHEEK_ALL_SIZE_X = "faceshape_cheek_all_size_x";// 脸颊宽度, 取值范围0.0-1.0,默认值0.5

//其他函数略

可以看到,上面数据基本包含所有人脸属性了,基本具备了捏脸能力,篇幅原因,我们这里不具体去实现。有这方面需求的读者,可以通过在界面上调整上面相关属性来实现。

接下来我们开始创建虚拟形象,首先创建一个User实体类:

public class User {

public String userName; //用户名

public String userId; //用户ID

public boolean isMan; //性别

public int width; //预览宽度

public int height; //预览高度

public int bgColor; //背景颜色

public int shirtIdx = 0; // T-shirt资源id

public int browIdx = 0; //眉毛资源id

public User(String userName, String userId, int width, int height) {

this.userName = userName;

this.userId = userId;

this.width = width;

this.height = height;

this.isMan = true;

bgColor = Color.argb(255, 33, 66, 99);

示例作用,为了简单起见,我们这里只针对眉毛和衣服资源做选取。接下来创建一个Activity:

public class AvatarActivity extends BaseActivity {

private int vWidth = 720;

private int vHeight = 1080;

private User user = new User("C_0001", "C_0001", vWidth, vHeight);

private TextureView mTextureView; //用于显示Avatar形象

private AvatarMngr mAvatarMngr; // 用于维护管理Avatar

private ColorPickerDialog colorPickerDialog; //用于背景色选取

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_avatar);

// 其他初始化界面相关代码略...

user.isMan = true;

mTextureView = findViewById(R.id.avatar_view);

mZegoMngr = ZegoMngr.getInstance(getApplication());

// 开启虚拟形象预览

mAvatarMngr.start(mTextureView, user);

最后一行代码中开启了虚拟形象预览,那么这里开启虚拟形象预览具体做了哪些工作呢?show me the code:

public class AvatarMngr implements ZegoAvatarServiceDelegate, RTCMngr.CaptureListener {

private static final String TAG = "AvatarMngr";

private static AvatarMngr mInstance;

private boolean mIsStop = false;

private User mUser = null;

private TextureBgRender mBgRender = null;

private OnAvatarServiceInitSucced listener;

private ZegoCharacterHelper mCharacterHelper;

private Application mApp;

public interface OnAvatarServiceInitSucced {

void onInitSucced();

public void setLicense(String license, OnAvatarServiceInitSucced listener) {

this.listener = listener;

ZegoAvatarService.addServiceObserver(this);

String aiPath = FileUtils.getPhonePath(mApp, "AIModel.bundle", "assets"); // AI 模型的绝对路径

ZegoServiceConfig config = new ZegoServiceConfig(license, aiPath);

ZegoAvatarService.init(mApp, config);

public void stop() {

mIsStop = true;

mUser = null;

stopExpression();

public void updateUser(User user) {

mUser = user;

if (user.shirtIdx == 0) {

mCharacterHelper.setPackage("m-shirt01");

} else {

mCharacterHelper.setPackage("m-shirt02");

if (user.browIdx == 0) {

mCharacterHelper.setPackage("brows_1");

} else {

mCharacterHelper.setPackage("brows_2");

* 启动Avatar,调用此函数之前,请确保已经调用过setLicense

* @param avatarView

public void start(TextureView avatarView, User user) {

mUser = user;

mIsStop = false;

initAvatar(avatarView, user);

startExpression();

private void initAvatar(TextureView avatarView, User user) {

String sex = ZegoCharacterHelper.MODEL_ID_MALE;

if (!user.isMan) sex = ZegoCharacterHelper.MODEL_ID_FEMALE;

// 创建 helper 简化调用

// base.bundle 是头模, human.bundle 是全身人模

mCharacterHelper = new ZegoCharacterHelper(FileUtils.getPhonePath(mApp, "human.bundle", "assets"));

mCharacterHelper.setExtendPackagePath(FileUtils.getPhonePath(mApp, "Packages", "assets"));

// 设置形象配置

mCharacterHelper.setDefaultAvatar(sex);

updateUser(user);

// 获取当前妆容数据, 可以保存到用户资料中

String json = mCharacterHelper.getAvatarJson();

// 启动表情检测

private void startExpression() {

// 启动表情检测前要申请摄像头权限, 这里是在 MainActivity 已经申请过了

ZegoAvatarService.getInteractEngine().startDetectExpression(ZegoExpressionDetectMode.Camera, expression -> {

// 表情直接塞给 avatar 驱动

mCharacterHelper.setExpression(expression);

// 停止表情检测

private void stopExpression() {

// 不用的时候记得停止

ZegoAvatarService.getInteractEngine().stopDetectExpression();

// 获取到 avatar 纹理后的处理

public void onCaptureAvatar(int textureId, int width, int height) {

if (mIsStop || mUser == null) { // rtc 的 onStop 是异步的, 可能activity已经运行到onStop了, rtc还没

return;

boolean useFBO = true;

if (mBgRender == null) {

mBgRender = new TextureBgRender(textureId, useFBO, width, height, Texture2dProgram.ProgramType.TEXTURE_2D_BG);

mBgRender.setInputTexture(textureId);

float r = Color.red(mUser.bgColor) / 255f;

float g = Color.green(mUser.bgColor) / 255f;

float b = Color.blue(mUser.bgColor) / 255f;

float a = Color.alpha(mUser.bgColor) / 255f;

mBgRender.setBgColor(r, g, b, a);

mBgRender.draw(useFBO); // 画到 fbo 上需要反向的

ZegoExpressEngine.getEngine().sendCustomVideoCaptureTextureData(mBgRender.getOutputTextureID(), width, height, System.currentTimeMillis());

@Override

public void onStartCapture() {

if (mUser == null) return;

// // 收到回调后,开发者需要执行启动视频采集相关的业务逻辑,例如开启摄像头等

AvatarCaptureConfig config = new AvatarCaptureConfig(mUser.width, mUser.height);

// // 开始捕获纹理

mCharacterHelper.startCaptureAvatar(config, this::onCaptureAvatar);

@Override

public void onStopCapture() {

mCharacterHelper.stopCaptureAvatar();

stopExpression();

private void initRes(Application app) {

// 先把资源拷贝到SD卡,注意:线上使用时,需要做一下判断,避免多次拷贝。资源也可以做成从网络下载。

if (!FileUtils.checkFile(app, "AIModel.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "AIModel.bundle", "assets");

if (!FileUtils.checkFile(app, "base.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "base.bundle", "assets");

if (!FileUtils.checkFile(app, "human.bundle", "assets"))

FileUtils.copyAssetsDir2Phone(app, "human.bundle", "assets");

if (!FileUtils.checkFile(app, "Packages", "assets"))

FileUtils.copyAssetsDir2Phone(app, "Packages", "assets");

@Override

public void onError(ZegoAvatarErrorCode code, String desc) {

Log.e(TAG, "errorcode : " + code.getErrorCode() + ",desc : " + desc);

@Override

public void onStateChange(ZegoAvatarServiceState state) {

if (state == ZegoAvatarServiceState.InitSucceed) {

Log.i("ZegoAvatar", "Init success");

// 要记得及时移除通知

ZegoAvatarService.removeServiceObserver(this);

if (listener != null) listener.onInitSucced();

private AvatarMngr(Application app) {

mApp = app;

initRes(app);

public static AvatarMngr getInstance(Application app) {

if (null == mInstance) {

synchronized (AvatarMngr.class) {

if (null == mInstance) {

mInstance = new AvatarMngr(app);

return mInstance;

以上代码完成了整个虚拟形象的创建,关键代码全部展示。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
中国的第四艘航母,排水量9.3万吨,到底会有哪些改进?

中国的第四艘航母,排水量9.3万吨,到底会有哪些改进?

文章侃娱乐
2024-05-12 15:07:46
石宏:俄朝关系快速升温,美国和北约怎么看?

石宏:俄朝关系快速升温,美国和北约怎么看?

直新闻
2024-06-20 00:29:19
你不觉得2000年以来,落后是有原因的吗?

你不觉得2000年以来,落后是有原因的吗?

北京作家编剧肥猪满圈
2024-04-30 17:47:01
4年3200万美元!雷迪克成湖人新帅,看齐勇士科尔?隆多或辅佐他

4年3200万美元!雷迪克成湖人新帅,看齐勇士科尔?隆多或辅佐他

李喜林篮球绝杀
2024-06-21 10:41:45
外媒:德国经济部长最新表态,称中国在所有领域都是重要合作伙伴

外媒:德国经济部长最新表态,称中国在所有领域都是重要合作伙伴

环球网资讯
2024-06-20 10:29:46
肖战和经纪人海外旅行?此举引粉丝猜测两人的关系!

肖战和经纪人海外旅行?此举引粉丝猜测两人的关系!

毒舌八卦
2024-06-20 21:54:47
朝鲜战场上的荷兰,60年未公开伤亡,直到2013年才公布

朝鲜战场上的荷兰,60年未公开伤亡,直到2013年才公布

文史达观
2024-06-21 06:45:03
呼和浩特5人被害,村民发声:他是光棍,身世可怜,曝杀人原因!

呼和浩特5人被害,村民发声:他是光棍,身世可怜,曝杀人原因!

皖声微言
2024-06-20 09:12:04
50岁富婆夜间约会帅哥,凌晨对方哀求“歇一会吧”,竟还心怀叵胎

50岁富婆夜间约会帅哥,凌晨对方哀求“歇一会吧”,竟还心怀叵胎

四象八卦
2024-06-20 16:42:28
震惊!旁边的同事,猝死了

震惊!旁边的同事,猝死了

蚂蚁大喇叭
2024-06-19 09:44:52
休赛赛,NBA的首笔交易来了!

休赛赛,NBA的首笔交易来了!

野球帝
2024-06-21 10:45:25
又有3个中国球员结束留洋回国!曾经都是希望,在欧洲难有竞争力

又有3个中国球员结束留洋回国!曾经都是希望,在欧洲难有竞争力

落夜足球
2024-06-20 22:36:54
纹身肚钉项链耳坠美甲俏皮小辫 吴艳妮晒金刚芭比造型直言日照见

纹身肚钉项链耳坠美甲俏皮小辫 吴艳妮晒金刚芭比造型直言日照见

劲爆体坛
2024-06-20 21:01:11
中美斗到现在,美方竟先喊停,对付美国人,还得用毛主席的打法

中美斗到现在,美方竟先喊停,对付美国人,还得用毛主席的打法

智慧天气通
2024-04-22 15:49:46
与杨紫分手1年,转身爱上毛晓慧的秦俊杰,现在过得怎么样?

与杨紫分手1年,转身爱上毛晓慧的秦俊杰,现在过得怎么样?

娱乐白名单
2024-06-21 10:37:09
题目难哭了?南京2024年中小学期末考试试卷来了!

题目难哭了?南京2024年中小学期末考试试卷来了!

南京择校
2024-06-20 22:52:53
罕见洪峰过境后的桂林

罕见洪峰过境后的桂林

澎湃新闻
2024-06-21 09:10:37
不叫暂停、不换人、听不懂英文!袁志比蔡斌更差!男教练太糟糕!

不叫暂停、不换人、听不懂英文!袁志比蔡斌更差!男教练太糟糕!

金毛爱女排
2024-06-21 05:09:57
真实的外蒙古有多离谱,“性旅游业”带动经济,靠出国黑工赚外汇

真实的外蒙古有多离谱,“性旅游业”带动经济,靠出国黑工赚外汇

文雅笔墨
2024-06-20 16:05:46
经济学女博士新职明确!她曾任佛山市发改局副局长12年

经济学女博士新职明确!她曾任佛山市发改局副局长12年

南方都市报
2024-06-21 08:10:14
2024-06-21 11:16:49
程序猿Wang
程序猿Wang
分享音视频技术,即构后台开发
2文章数 0关注度
往期回顾 全部

科技要闻

美媒:苹果正与百度阿里百川等谈AI合作

头条要闻

环球:欧盟若对华抡起贸易大棒 中国不会被动挨打

头条要闻

环球:欧盟若对华抡起贸易大棒 中国不会被动挨打

体育要闻

1-0"吊打"意大利 西班牙这就叫冠军相?

娱乐要闻

陈晓惹争议!被曝婚变离家出走冷暴力

财经要闻

普华永道,引火烧身

汽车要闻

售价11.79-14.39万元 新一代哈弗H6正式上市

态度原创

手机
教育
房产
亲子
公开课

手机要闻

一加夏季性能生态新品发布会定档 6 月 27 日,Ace 3 Pro 等将至

教育要闻

一手拿画笔,一手带娃,当画画成为全职妈妈的“出口”

房产要闻

海棠湾!一所重量级国际学校真的来了!

亲子要闻

鸡娃狂潮下的悲剧:北京每年有两万名儿童,走进安定医院

公开课

近视只是视力差?小心并发症

无障碍浏览 进入关怀版