autojs把输入法合并到app中

简介: 牙叔教程 简单易懂

牙叔教程 简单易懂

为什么要合并

上一个教程是 autojs输入法 , 我们要使用的话, 需要两个app:

  • 脚本打包后的app
  • 输入法app

有的人觉得安装两个app麻烦, 我觉得还好, 毕竟输入法装一次就可以永久使用了.

但是有的人就不想安装两个app, 那么我们就把输入法合并到app里面吧;

这里的合并的两个app指的是

  • 你写的脚本打包后的app
  • 你自己写的输入法app


你能合并别人写的输入法吗?

比如搜狗输入法, qq输入法,等等?

答: 不能

因为别人的输入法有太多太多的资源文件和代码, 各种代码之间互相依赖,

根本无从下手的好吗;

况且, 人家肯定加密混淆了, 估计还得反编译, 一般人没那个技术;

只有你自己写的输入法, 剔肉去骨, 只添加必要的文件, 做一个非常非常简单的安卓输入法工程:

  • 一个输入法界面
  • 一个 继承 InputMethodService 的类
  • 几个 xml 文件

使用到的软件

  • mt管理器  版本: 2.10.4
  • 输入法app
  • autojs 版本: 8.8.22
  • autojs打包后的app

合并步骤

  1. 打包一个app用来调试脚本

我们只有一个单文件, 打包也用单文件,

用项目方式打包也可以, 基本没区别

"ui";
ui.layout(
  <vertical>
    <text gravity="center" textStyle="bold" textSize="30sp">
      牙叔出品
    </text>
    <input id="代码内容" w="*"></input>
    <button id="执行代码">执行代码</button>
    <input id="脚本文件路径" w="*"></input>
    <button id="执行脚本文件">执行脚本文件</button>
    <input id="项目入口文件路径" w="*"></input>
    <button id="执行项目">执行项目</button>
    <button id="日志">日志</button>
    <button id="停止脚本" text="停止脚本"></button>
  </vertical>
);
ui.代码内容.setText('toastLog("hello");');
ui.脚本文件路径.setText("/sdcard/脚本/main.js");
ui.项目入口文件路径.setText("/sdcard/脚本/测试/main.js");
ui.执行代码.click(function () {
  eval(ui.代码内容.text());
});
ui.执行脚本文件.click(function () {
  engines.execScriptFile(ui.脚本文件路径.text().trim());
});
ui.执行项目.click(function () {
  let entryFilePath = ui.项目入口文件路径.text().trim();
  engines.execScriptFile(entryFilePath, { path: entryFilePath.replace(/\/[\w.]+?$/, "") });
});
ui.日志.click(function () {
  app.startActivity("console");
});
ui.停止脚本.click(function () {
  engines.all().map((ScriptEngine) => {
    if (engines.myEngine().toString() !== ScriptEngine.toString()) {
      ScriptEngine.forceStop();
    }
  });
});


  1. 使用mt管理器打开输入法app的应用清AndroidManifest.xml, 添加组件
<service android:label="@string/yashu_ime_label" android:name="com.yashu66.input.YashuIME" android:permission="android.permission.BIND_INPUT_METHOD" android:exported="true">
  <intent-filter>
    <action android:name="android.view.InputMethod" />
  </intent-filter>
  <meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>


标签在 标签内部

<application>
  <service></service>
</application>


注意从这里开始, 就有了引用, 比如

android:label="@string/yashu_ime_label"


我们要尽量简化我们的操作, 能不引用的尽量不引用;

这个labe的值, 指向的就是一个字符串, 我们直接改为

android:label="牙叔教程"


还有一个引用是

android:resource="@xml/method"


这个没辙, 对应的method.xml文件代码太多, 必须添加到打包后的app里面

method.xml文件内容


上图左侧是autojs打包后的app的res文件夹

右侧是输入法的res文件夹

在app的res文件夹中, 并没有xml文件,

输入法的res文件夹中, 有xml文件,

因此我们在把右侧的xml文件夹, 添加到左侧的res文件夹中;

到此为止, 左侧就有了 method.xml 这个文件实体,

有了实体, 还不够,, 还要在对应的位置添加正确的id,

我们先把所有的输入法依赖的实体都添加进去, id稍后再说.

  1. 右侧res/layout/key_layout.xml添加到左侧res/

  1. 右侧res/drawable/test_selector.xml添加到左侧res/

  1. 添加classes2.dex改成classes3.dex, 添加到左侧

  1. 打开输入法的安卓工程, 查看 YashuIME这个类的第118行, 这里引用了键盘界面
View myKeyboardView = (ViewGroup) LayoutInflater.from(this).inflate(R.layout.key_layout, null);


用mt查看classes3.dex中对应的代码, 是这样的

View myKeyboardView = (ViewGroup) LayoutInflater.from(this).inflate(0x7f0b002e, (ViewGroup) null);

设置0x7f0b002e

  1. 我们在输入法app的 resources.arsc 中搜索, 都有哪些地方包含了 0x7f0b002e

搜索资源ID

第一个

<path name="key_layout">res/layout/key_layout.xml</path>


第二个

<entry id="0x7f0b002e" name="key_layout" />


我们可以认为这个资源的调用流程是这样的

View myKeyboardView = (ViewGroup) LayoutInflater.from(this).inflate(R.layout.key_layout, null);
->
<entry id="0x7f0b002e" name="key_layout" />
->
<path name="key_layout">res/layout/key_layout.xml</path>


现在我们去左侧的输入法, 按照这个流程添加ID, 倒着来,

先添加path, 再添加entry, 再把修改classes.dex中的id

为防止id太小引发冲突, 我们一律增加id,

意思就是比如左侧最后一个id是10, 我们就新增id 11

添加path

<path name="key_layout">res/key_layout.xml</path>


再添加entry

<entry id="0x7f0c00a2" name="key_layout" />


修改classes.dex中的id

改为

const v1, 0x7f0c00a2

改完了吗?

做梦呢你, 清醒点, 还有好几步呢!

key_layout.xml是输入法界面, 它里面有两个id

style="@7f0f02a0"
style="@7f0f029f"



同理, 我们去输入法的resources.arsc搜索资源ID

先处理  7f0f02a0


style

<style name="layout_input_amount_style">
  <item name="android:gravity">
    center
  </item>
  ...
</style>


type-info

<entry id="0x7f0f02a0" name="layout_input_amount_style" />


左侧对应的文件中, 添加style和type-info

修改原则, 一律在文件底部添加.

style就直接复制黏贴, 注意不要格式化, 原样复制即可, 否则可能报错;

type-info需要修改id


此处最后一个id是ea, 新增+1, 就是eb


同理, 处理 7f0f029f


添加style保存并退出的时候会报错, 说找不到test_selector

<item name="android:background">@drawable/test_selector</item>


此时我们随便写个颜色#ffff00保存退出,

去右侧搜索 test_selector


又得添加一个ID, 这次是给drawable里面添加

<path name="test_selector">res/test_selector.xml</path>


test_selector添加完成后, 把上面的颜色改回去

<item name="android:background">@drawable/test_selector</item>


这次保存退出的时候, 就不会报刚才那个错误了: 找不到test_selector

安装合并了输入法的app, 看看效果


很不幸, 没有我们的输入法, 修改失败


应该是遗漏了哪里


先看看清单文件, 结果发现, 刚才嘴上说要添加service, 结果并没有添加,

现在把service添加进去

<service android:label="牙叔教程" android:name="com.yashu66.input.YashuIME" android:permission="android.permission.BIND_INPUT_METHOD" android:exported="true">
  <intent-filter>
    <action android:name="android.view.InputMethod" />
  </intent-filter>
  <meta-data android:name="android.view.im" android:resource="@xml/method" />
</service>


保存的时候, 报错了


去右侧查询一下资源ID


搜一下7F110000


<entry id="0x7f110000" name="method" />



对应的path




如法炮制, 左侧添加该资源

添加完之后, 再去清单中添加service,, 这次就不会报错了


卸载刚才安装的app, 安装刚修改好的app, 看看效果

棒啊, 终于出现我们输入法的名字了

设置为默认输入法, 测试输入效果

报错说必须提供宽度属性, 我们打开文件看看

确实没有宽度, 这个abc_seekbar_track_material也不知道从哪里冒出来的,

我们重新把右侧的key_layout.xml文件添加到左侧, 结果还是和原来一样

看看这个 abc_seekbar_track_material 是什么


<path name="abc_seekbar_track_material">res/J71.xml</path>



啥也不是, 完全没关系


key_layout.xml是输入法界面, 每个按键都有id, 因此我们要批量添加按键的ID


要添加许多ID, 26个字母+数字+特殊键,

必须写个脚本自动生成, 不然手敲累死了,

十六进制递增


var template = '<entry id="0x_hex" name="btn_name" />';
let btnsList = ["0123456789", "qwertyuiop", "asdfghjkl", "zxcvbnm"];
var len = btnsList.length;
let xmls = [];
let _hex = "7f0901df";
for (var i = 0; i < len; i++) {
  let btns = btnsList[i];
  for (var j = 0; j < btns.length; j++) {
    _hex = incrementHex(_hex);
    let btnXml = generateBtnXml(btns[j], _hex);
    xmls.push(btnXml);
  }
}
log(xmls.join("\n"));
function generateBtnXml(_name, _hex) {
  let btnXml = template.replace(/_name/, _name).replace(/_hex/, _hex);
  return btnXml;
}
function incrementHex(hex) {
  let value = java.lang.Integer.parseInt(hex, 16);
  value++;
  return java.lang.Integer.toHexString(value);
}


批量添加按键资源以后, 安装app测试


我们看看125行的代码

int resID = getResources().getIdentifier(btnId, "id", "com.yashu66.input");


我猜是这个包名应该换成脚本打包的包名

com.example.script1649662595863


再次安装测试

漂亮

终于搞好了, 打字没问题, 特殊按键也没问题,

下面来测试广播调用输入法


intent = new Intent();
intent.setAction("com.yashu66.input");
for (var i = 0; i < 2; i++) {
  intent.putExtra("value", "公众号: 牙叔教程");
  context.sendBroadcast(intent);
  sleep(666);
}
for (var i = 0; i < 10; i++) {
  intent.putExtra("value", "del");
  context.sendBroadcast(intent);
  sleep(111);
}
intent.putExtra("value", "clear");
context.sendBroadcast(intent);
sleep(1000);
intent.putExtra("value", "公众号: 牙叔教程");
context.sendBroadcast(intent);
intent.putExtra("value", "enter");
context.sendBroadcast(intent);


完美

我宣布, 合并成功

备注

不同的autojs版本打包的app, 略有差异,

合并步骤类似


名人名言

思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程

声明

部分内容来自网络 本教程仅用于学习, 禁止用于其他用途



相关文章
|
数据安全/隐私保护
hook逆向autojs离线Dex加密的app(三)
hook逆向autojs离线Dex加密的app(三)
480 0
|
5月前
|
数据安全/隐私保护
基于AutoJs实现的薅羊毛App专业版源码大分享---更新啦
基于AutoJs实现的薅羊毛App专业版源码大分享---更新啦
138 0
|
5月前
|
存储 缓存 JavaScript
基于AutoJs实现的薅羊毛App专业版源码大分享
基于AutoJs实现的薅羊毛App专业版源码大分享
138 0
|
数据安全/隐私保护
hook逆向autojs离线Dex加密的app(二)
hook逆向autojs离线Dex加密的app(二)
711 0
hook逆向autojs离线Dex加密的app(二)
|
测试技术 Android开发
autojs启动app最稳定的方法
牙叔教程 简单易懂
2388 0
|
JavaScript 数据安全/隐私保护
hook逆向autojs离线Dex加密的app(七)
hook逆向autojs离线Dex加密的app(七)
406 0
|
数据安全/隐私保护
hook逆向autojs离线Dex加密的app(六)
hook逆向autojs离线Dex加密的app(六)
279 0
|
数据安全/隐私保护
hook逆向autojs离线Dex加密的app(五)
hook逆向autojs离线Dex加密的app(五)
417 0
|
数据安全/隐私保护
hook逆向autojs离线Dex加密的app(四)
hook逆向autojs离线Dex加密的app(四)
307 0
|
5天前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
78 7