前几天听说了个 jniroot, 貌似很厉害的样子
https://github.com/topjohnwu/libsu
想着能不能适配 imgui.
干就完事了.
改进后的 libsu 模板在这里
https://github.com/PShocker/libsutemplate
1. 新建 Native C++ 项目,把 libsu 的依赖全部加进去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } repositories { maven { url 'https://jitpack.io' } } dependencies { def libsuVersion = '4.0.3' implementation "com.github.topjohnwu.libsu:core:${libsuVersion}" implementation "com.github.topjohnwu.libsu:service:${libsuVersion}" implementation "com.github.topjohnwu.libsu:io:${libsuVersion}" implementation "com.github.topjohnwu.libsu:busybox:${libsuVersion}" }
若报错,把 maven { url ‘https://jitpack.io ’ } 添加到 settings.gradle 里
1 2 3 4 5 6 7 8 dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url 'https://jitpack.io' } } }
2. 新建 aidl 文件,Rebuild 生成 Stub 文件
1 2 3 4 5 6 7 8 9 interface IImGuiService { void init_ImGui (inout Surface surface) ; void update_ImGui (int width, int height) ; void set_ImGui_Orientation (int orientation) ; }
新建 AIDLService 类,继承 RootService.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class AIDLService extends RootService { static { if (Process.myUid() == 0 ) System.loadLibrary("imgui" ); } public native void native_init_ImGui (Surface surface) ; public native void native_update_ImGui (int width, int height) ; public native void native_set_ImGui_Orientation (int orientation) ; class ImGui extends IImGuiService .Stub { @Override public void init_ImGui (Surface surface) throws RemoteException { native_init_ImGui(surface); } @Override public void update_ImGui (int width, int height) throws RemoteException { native_update_ImGui(width,height); } @Override public void set_ImGui_Orientation (int orientation) throws RemoteException { native_set_ImGui_Orientation(orientation); } } @Override public IBinder onBind (@NonNull Intent intent) { return new ImGui (); } }
3. 新建 ImGuiView 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class ImGuiView extends SurfaceView implements SurfaceHolder .Callback{ public ImGuiView (Context context) { super (context); setZOrderOnTop(true ); SurfaceHolder holder = getHolder(); holder.setFormat(PixelFormat.TRANSLUCENT); getHolder().addCallback(this ); setFocusable(true ); setFocusableInTouchMode(true ); requestFocus(); requestFocusFromTouch(); } @Override public void surfaceCreated (@NonNull SurfaceHolder surfaceHolder) { Log.d("Shocker" ,"surfaceCreated" ); new Thread (new Runnable () { @Override public void run () { try { MainActivity.ImGui.init_ImGui(surfaceHolder.getSurface()); } catch (RemoteException e) { e.printStackTrace(); } } }).start(); } @Override public void surfaceChanged (@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) { ....... } @Override public void surfaceDestroyed (@NonNull SurfaceHolder surfaceHolder) { } }
4. 新建 AIDLConnection 类,在 MainActivity 的 OnCreate 里绑定 RootService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static IImGuiService ImGui;class AIDLConnection implements ServiceConnection { private final boolean isDaemon; AIDLConnection(boolean b) { isDaemon = b; } @Override public void onServiceConnected (ComponentName name, IBinder service) { ImGui= IImGuiService.Stub.asInterface(service); Log.d("Shocker" ,"Connected" ); } @Override public void onServiceDisconnected (ComponentName componentName) { Log.d("Shocker" ,"Disconnected" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 protected void addFullView () { ImGuiView imGuiView=new ImGuiView (this ); params = new WindowManager .LayoutParams( getLayoutType(), WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_FULLSCREEN, PixelFormat.TRANSLUCENT); params.gravity = Gravity.LEFT | Gravity.TOP; params.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; params.x = 0 ; params.y = 0 ; params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.MATCH_PARENT; if (Build.VERSION.SDK_INT >= 28 ) { params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES ; } windowManager.addView(imGuiView, params); }
1 2 3 4 5 6 7 8 9 10 11 @Override protected void onCreate (Bundle savedInstanceState) { .............. RootService.bind(new Intent (this , AIDLService.class), new AIDLConnection (false )); t.setOnClickListener(view -> { if (!start){ addFullView(); start=true ; } }); }
5.native 完成 imgui 初始化,循环读取输入和渲染
1 2 3 4 5 6 7 8 9 10 Java_com_shocker_imgui_AIDLService_native_1init_1ImGui (JNIEnv *env, jobject thiz, jobject surface) { ANativeWindow* w = ANativeWindow_fromSurface (env, (jobject)surface); init (w); ANativeWindow_release (w); while (true ){ handleInputEvent (); tick (); } }