You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在应用中嵌入其他应用并叠加布局(附BlockLauncher参考案例)

嘿,很高兴你参考了BlockLauncher这个项目——我正好研究过它的源码,它实现内嵌游戏的核心逻辑其实是围绕原生库加载+游戏视图嵌入来做的,给你一步步拆解具体怎么实现:

核心实现思路拆解

步骤1:准备游戏原生库文件

首先你得拿到目标游戏的原生库(一般是.so格式),这些文件对应不同的CPU架构(比如arm64-v8a、armeabi-v7a)。把它们放到Android项目的src/main/jniLibs目录下,这样打包时会自动适配不同设备的架构,包含对应的库文件。

步骤2:加载游戏原生库

BlockLauncher主要用System.loadLibrary()来加载库,这个方法不需要写绝对路径,只需要传入库名(比如游戏库叫libgame.so,就传"game")。你可以在自定义的Application类或者游戏承载Activity的onCreate()方法里提前加载:

static {
    try {
        // 按依赖顺序加载库,先加载依赖库再加载主游戏库
        System.loadLibrary("game_dependency");
        System.loadLibrary("game");
    } catch (UnsatisfiedLinkError e) {
        e.printStackTrace();
        // 处理加载失败的情况,比如提示用户安装对应架构的版本
    }
}

如果你的库文件不在默认路径,也可以用System.load()传入绝对路径,但适配性不如前者,不推荐。

步骤3:嵌入游戏视图

加载库之后,游戏通常会提供一个可嵌入的View(比如SurfaceView或者自定义GameView),或者需要你继承游戏的主Activity。比如BlockLauncher就是继承了Minecraft的主Activity,然后在里面插入自己的逻辑。

如果是View形式,你可以直接在自己的布局里嵌套:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!-- 游戏主视图 -->
    <com.game.GameView
        android:id="@+id/game_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- 用于放置悬浮按钮的容器,层级在游戏之上 -->
    <RelativeLayout
        android:id="@+id/overlay_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

步骤4:实现悬浮操作按钮

悬浮按钮需要脱离Activity的窗口层级,用WindowManager创建全局窗口,这样游戏全屏时也能显示。核心步骤:

  1. 申请SYSTEM_ALERT_WINDOW权限(Android 6.0以上需要动态申请,还要引导用户到系统设置里开启);
  2. 创建按钮布局(比如一个ImageView或FloatingActionButton);
  3. 通过WindowManager.LayoutParams设置窗口类型(比如TYPE_APPLICATION_OVERLAY)和位置参数;
  4. 添加到WindowManager并绑定点击事件(比如触发截图)。

示例代码片段:

WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
ImageView fabScreenshot = new ImageView(this);
fabScreenshot.setImageResource(R.drawable.ic_screenshot);

WindowManager.LayoutParams params = new WindowManager.LayoutParams(
    WindowManager.LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.WRAP_CONTENT,
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
        WindowManager.LayoutParams.TYPE_PHONE,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
    PixelFormat.TRANSLUCENT
);
params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
params.x = 20;
params.y = 20;

windowManager.addView(fabScreenshot, params);

fabScreenshot.setOnClickListener(v -> takeScreenshot());

步骤5:实现截图功能

如果游戏用普通View渲染,直接用getDrawingCache()就能获取截图:

private void takeScreenshot() {
    View gameView = findViewById(R.id.game_view);
    gameView.setDrawingCacheEnabled(true);
    Bitmap bitmap = Bitmap.createBitmap(gameView.getDrawingCache());
    gameView.setDrawingCacheEnabled(false);
    // 保存截图到本地
    saveBitmapToFile(bitmap);
}

但如果是SurfaceView或OpenGL渲染的游戏,getDrawingCache()会失效,这时候要用MediaProjection API实现全局截图(需要用户授权,是Android官方推荐的稳定方案)。

步骤6:其他工具集成

比如帧率显示,可以通过Choreographer监听帧回调计算帧率,再显示在悬浮窗;快捷设置(比如调整画质、音量)则需要调用游戏暴露的JNI接口,或者通过反射调用内部方法(注意兼容性,不同游戏逻辑差异大)。

关键注意事项

  • 权限适配:除了悬浮窗权限,保存截图需要WRITE_EXTERNAL_STORAGE权限(Android 10+可以用MediaStore替代);
  • 兼容性:不同游戏的库结构、视图逻辑差异很大,你可能需要像BlockLauncher那样,针对目标游戏做定制化适配;
  • 性能优化:游戏本身资源消耗大,你的内嵌工具要尽量轻量化,比如Activity销毁时及时移除悬浮窗,后台时暂停游戏避免耗电。

内容的提问来源于stack exchange,提问作者Han Programer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:06:14