@aiscene/android 1.6.4 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/midscene-android +2 -0
- package/bin/yadb +0 -0
- package/dist/es/cli.mjs +56 -2
- package/dist/es/index.mjs +55 -1
- package/dist/es/mcp-server.mjs +56 -2
- package/dist/lib/cli.js +56 -2
- package/dist/lib/index.js +55 -1
- package/dist/lib/mcp-server.js +56 -2
- package/dist/types/index.d.ts +10 -0
- package/dist/types/mcp-server.d.ts +10 -0
- package/package.json +1 -1
- package/bin/AndroidManifest.xml +0 -0
- package/bin/META-INF/com/android/build/gradle/app-metadata.properties +0 -2
- package/bin/classes.dex +0 -0
- package/bin/resources.arsc +0 -0
package/bin/yadb
ADDED
|
Binary file
|
package/dist/es/cli.mjs
CHANGED
|
@@ -932,7 +932,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
932
932
|
async execYadb(keyboardContent) {
|
|
933
933
|
await this.ensureYadb();
|
|
934
934
|
const adb = await this.getAdb();
|
|
935
|
-
|
|
935
|
+
try {
|
|
936
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
937
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
938
|
+
await adb.shell(command);
|
|
939
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
940
|
+
} catch (error) {
|
|
941
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
942
|
+
if (isAccessibilityConflict) {
|
|
943
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
944
|
+
await this.inputViaClipboard(keyboardContent);
|
|
945
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
async inputViaClipboard(text) {
|
|
949
|
+
const adb = await this.getAdb();
|
|
950
|
+
try {
|
|
951
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
952
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
953
|
+
const setClipboardCmd = `
|
|
954
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
955
|
+
`;
|
|
956
|
+
await adb.shell(setClipboardCmd);
|
|
957
|
+
await sleep(100);
|
|
958
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
959
|
+
await sleep(100);
|
|
960
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
961
|
+
} catch (error1) {
|
|
962
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
963
|
+
try {
|
|
964
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
965
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
966
|
+
await sleep(100);
|
|
967
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
968
|
+
await sleep(100);
|
|
969
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
970
|
+
} catch (error2) {
|
|
971
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
972
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
973
|
+
if (isPureAscii) {
|
|
974
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
975
|
+
await adb.inputText(text);
|
|
976
|
+
} else await this.inputCharByChar(text);
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
async inputCharByChar(text) {
|
|
981
|
+
const adb = await this.getAdb();
|
|
982
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
983
|
+
const chars = Array.from(text);
|
|
984
|
+
for (const char of chars){
|
|
985
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
986
|
+
else await adb.shell(`input text "${char}"`);
|
|
987
|
+
await sleep(50);
|
|
988
|
+
}
|
|
989
|
+
debugDevice("Character-by-character input completed");
|
|
936
990
|
}
|
|
937
991
|
async getElementsInfo() {
|
|
938
992
|
return [];
|
|
@@ -1865,7 +1919,7 @@ class AndroidMidsceneTools extends BaseMidsceneTools {
|
|
|
1865
1919
|
const tools = new AndroidMidsceneTools();
|
|
1866
1920
|
runToolsCLI(tools, 'midscene-android', {
|
|
1867
1921
|
stripPrefix: 'android_',
|
|
1868
|
-
version: "1.6.
|
|
1922
|
+
version: "1.6.6"
|
|
1869
1923
|
}).catch((e)=>{
|
|
1870
1924
|
if (!(e instanceof CLIError)) console.error(e);
|
|
1871
1925
|
process.exit(e instanceof CLIError ? e.exitCode : 1);
|
package/dist/es/index.mjs
CHANGED
|
@@ -835,7 +835,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
835
835
|
async execYadb(keyboardContent) {
|
|
836
836
|
await this.ensureYadb();
|
|
837
837
|
const adb = await this.getAdb();
|
|
838
|
-
|
|
838
|
+
try {
|
|
839
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
840
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
841
|
+
await adb.shell(command);
|
|
842
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
845
|
+
if (isAccessibilityConflict) {
|
|
846
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
847
|
+
await this.inputViaClipboard(keyboardContent);
|
|
848
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async inputViaClipboard(text) {
|
|
852
|
+
const adb = await this.getAdb();
|
|
853
|
+
try {
|
|
854
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
855
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
856
|
+
const setClipboardCmd = `
|
|
857
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
858
|
+
`;
|
|
859
|
+
await adb.shell(setClipboardCmd);
|
|
860
|
+
await sleep(100);
|
|
861
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
862
|
+
await sleep(100);
|
|
863
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
864
|
+
} catch (error1) {
|
|
865
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
866
|
+
try {
|
|
867
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
868
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
869
|
+
await sleep(100);
|
|
870
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
871
|
+
await sleep(100);
|
|
872
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
873
|
+
} catch (error2) {
|
|
874
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
875
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
876
|
+
if (isPureAscii) {
|
|
877
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
878
|
+
await adb.inputText(text);
|
|
879
|
+
} else await this.inputCharByChar(text);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
async inputCharByChar(text) {
|
|
884
|
+
const adb = await this.getAdb();
|
|
885
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
886
|
+
const chars = Array.from(text);
|
|
887
|
+
for (const char of chars){
|
|
888
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
889
|
+
else await adb.shell(`input text "${char}"`);
|
|
890
|
+
await sleep(50);
|
|
891
|
+
}
|
|
892
|
+
debugDevice("Character-by-character input completed");
|
|
839
893
|
}
|
|
840
894
|
async getElementsInfo() {
|
|
841
895
|
return [];
|
package/dist/es/mcp-server.mjs
CHANGED
|
@@ -931,7 +931,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
931
931
|
async execYadb(keyboardContent) {
|
|
932
932
|
await this.ensureYadb();
|
|
933
933
|
const adb = await this.getAdb();
|
|
934
|
-
|
|
934
|
+
try {
|
|
935
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
936
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
937
|
+
await adb.shell(command);
|
|
938
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
939
|
+
} catch (error) {
|
|
940
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
941
|
+
if (isAccessibilityConflict) {
|
|
942
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
943
|
+
await this.inputViaClipboard(keyboardContent);
|
|
944
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
async inputViaClipboard(text) {
|
|
948
|
+
const adb = await this.getAdb();
|
|
949
|
+
try {
|
|
950
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
951
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
952
|
+
const setClipboardCmd = `
|
|
953
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
954
|
+
`;
|
|
955
|
+
await adb.shell(setClipboardCmd);
|
|
956
|
+
await sleep(100);
|
|
957
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
958
|
+
await sleep(100);
|
|
959
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
960
|
+
} catch (error1) {
|
|
961
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
962
|
+
try {
|
|
963
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
964
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
965
|
+
await sleep(100);
|
|
966
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
967
|
+
await sleep(100);
|
|
968
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
969
|
+
} catch (error2) {
|
|
970
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
971
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
972
|
+
if (isPureAscii) {
|
|
973
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
974
|
+
await adb.inputText(text);
|
|
975
|
+
} else await this.inputCharByChar(text);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
async inputCharByChar(text) {
|
|
980
|
+
const adb = await this.getAdb();
|
|
981
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
982
|
+
const chars = Array.from(text);
|
|
983
|
+
for (const char of chars){
|
|
984
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
985
|
+
else await adb.shell(`input text "${char}"`);
|
|
986
|
+
await sleep(50);
|
|
987
|
+
}
|
|
988
|
+
debugDevice("Character-by-character input completed");
|
|
935
989
|
}
|
|
936
990
|
async getElementsInfo() {
|
|
937
991
|
return [];
|
|
@@ -1868,7 +1922,7 @@ class AndroidMCPServer extends BaseMCPServer {
|
|
|
1868
1922
|
constructor(toolsManager){
|
|
1869
1923
|
super({
|
|
1870
1924
|
name: '@midscene/android-mcp',
|
|
1871
|
-
version: "1.6.
|
|
1925
|
+
version: "1.6.6",
|
|
1872
1926
|
description: 'Control the Android device using natural language commands'
|
|
1873
1927
|
}, toolsManager);
|
|
1874
1928
|
}
|
package/dist/lib/cli.js
CHANGED
|
@@ -947,7 +947,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
947
947
|
async execYadb(keyboardContent) {
|
|
948
948
|
await this.ensureYadb();
|
|
949
949
|
const adb = await this.getAdb();
|
|
950
|
-
|
|
950
|
+
try {
|
|
951
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
952
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
953
|
+
await adb.shell(command);
|
|
954
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
955
|
+
} catch (error) {
|
|
956
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
957
|
+
if (isAccessibilityConflict) {
|
|
958
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
959
|
+
await this.inputViaClipboard(keyboardContent);
|
|
960
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
async inputViaClipboard(text) {
|
|
964
|
+
const adb = await this.getAdb();
|
|
965
|
+
try {
|
|
966
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
967
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
968
|
+
const setClipboardCmd = `
|
|
969
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
970
|
+
`;
|
|
971
|
+
await adb.shell(setClipboardCmd);
|
|
972
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
973
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
974
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
975
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
976
|
+
} catch (error1) {
|
|
977
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
978
|
+
try {
|
|
979
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
980
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
981
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
982
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
983
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
984
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
985
|
+
} catch (error2) {
|
|
986
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
987
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
988
|
+
if (isPureAscii) {
|
|
989
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
990
|
+
await adb.inputText(text);
|
|
991
|
+
} else await this.inputCharByChar(text);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
async inputCharByChar(text) {
|
|
996
|
+
const adb = await this.getAdb();
|
|
997
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
998
|
+
const chars = Array.from(text);
|
|
999
|
+
for (const char of chars){
|
|
1000
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
1001
|
+
else await adb.shell(`input text "${char}"`);
|
|
1002
|
+
await (0, core_utils_namespaceObject.sleep)(50);
|
|
1003
|
+
}
|
|
1004
|
+
debugDevice("Character-by-character input completed");
|
|
951
1005
|
}
|
|
952
1006
|
async getElementsInfo() {
|
|
953
1007
|
return [];
|
|
@@ -1880,7 +1934,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1880
1934
|
const tools = new AndroidMidsceneTools();
|
|
1881
1935
|
(0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-android', {
|
|
1882
1936
|
stripPrefix: 'android_',
|
|
1883
|
-
version: "1.6.
|
|
1937
|
+
version: "1.6.6"
|
|
1884
1938
|
}).catch((e)=>{
|
|
1885
1939
|
if (!(e instanceof cli_namespaceObject.CLIError)) console.error(e);
|
|
1886
1940
|
process.exit(e instanceof cli_namespaceObject.CLIError ? e.exitCode : 1);
|
package/dist/lib/index.js
CHANGED
|
@@ -868,7 +868,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
868
868
|
async execYadb(keyboardContent) {
|
|
869
869
|
await this.ensureYadb();
|
|
870
870
|
const adb = await this.getAdb();
|
|
871
|
-
|
|
871
|
+
try {
|
|
872
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
873
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
874
|
+
await adb.shell(command);
|
|
875
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
876
|
+
} catch (error) {
|
|
877
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
878
|
+
if (isAccessibilityConflict) {
|
|
879
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
880
|
+
await this.inputViaClipboard(keyboardContent);
|
|
881
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
async inputViaClipboard(text) {
|
|
885
|
+
const adb = await this.getAdb();
|
|
886
|
+
try {
|
|
887
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
888
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
889
|
+
const setClipboardCmd = `
|
|
890
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
891
|
+
`;
|
|
892
|
+
await adb.shell(setClipboardCmd);
|
|
893
|
+
await (0, utils_namespaceObject.sleep)(100);
|
|
894
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
895
|
+
await (0, utils_namespaceObject.sleep)(100);
|
|
896
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
897
|
+
} catch (error1) {
|
|
898
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
899
|
+
try {
|
|
900
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
901
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
902
|
+
await (0, utils_namespaceObject.sleep)(100);
|
|
903
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
904
|
+
await (0, utils_namespaceObject.sleep)(100);
|
|
905
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
906
|
+
} catch (error2) {
|
|
907
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
908
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
909
|
+
if (isPureAscii) {
|
|
910
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
911
|
+
await adb.inputText(text);
|
|
912
|
+
} else await this.inputCharByChar(text);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
async inputCharByChar(text) {
|
|
917
|
+
const adb = await this.getAdb();
|
|
918
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
919
|
+
const chars = Array.from(text);
|
|
920
|
+
for (const char of chars){
|
|
921
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
922
|
+
else await adb.shell(`input text "${char}"`);
|
|
923
|
+
await (0, utils_namespaceObject.sleep)(50);
|
|
924
|
+
}
|
|
925
|
+
debugDevice("Character-by-character input completed");
|
|
872
926
|
}
|
|
873
927
|
async getElementsInfo() {
|
|
874
928
|
return [];
|
package/dist/lib/mcp-server.js
CHANGED
|
@@ -962,7 +962,61 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
962
962
|
async execYadb(keyboardContent) {
|
|
963
963
|
await this.ensureYadb();
|
|
964
964
|
const adb = await this.getAdb();
|
|
965
|
-
|
|
965
|
+
try {
|
|
966
|
+
const command = `app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`;
|
|
967
|
+
debugDevice(`Executing YADB input: "${keyboardContent}"`);
|
|
968
|
+
await adb.shell(command);
|
|
969
|
+
debugDevice(`YADB input completed: "${keyboardContent}"`);
|
|
970
|
+
} catch (error) {
|
|
971
|
+
const isAccessibilityConflict = error?.cause?.stderr?.includes('UiAutomationService') || error?.cause?.stderr?.includes('already registered') || error?.message?.includes('UiAutomationService');
|
|
972
|
+
if (isAccessibilityConflict) {
|
|
973
|
+
debugDevice("YADB failed due to AccessibilityService conflict (likely Appium running), falling back to clipboard method");
|
|
974
|
+
await this.inputViaClipboard(keyboardContent);
|
|
975
|
+
} else debugDevice(`YADB execution may have completed despite error: ${error}`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async inputViaClipboard(text) {
|
|
979
|
+
const adb = await this.getAdb();
|
|
980
|
+
try {
|
|
981
|
+
debugDevice(`Inputting via clipboard: "${text}"`);
|
|
982
|
+
const escapedText = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
983
|
+
const setClipboardCmd = `
|
|
984
|
+
content insert --uri content://settings/system --bind name:s:clipboard_text --bind value:s:"${escapedText}"
|
|
985
|
+
`;
|
|
986
|
+
await adb.shell(setClipboardCmd);
|
|
987
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
988
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
989
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
990
|
+
debugDevice(`Clipboard input completed via content provider: "${text}"`);
|
|
991
|
+
} catch (error1) {
|
|
992
|
+
debugDevice(`Content provider clipboard failed, trying clipper app: ${error1}`);
|
|
993
|
+
try {
|
|
994
|
+
const base64Text = Buffer.from(text, 'utf-8').toString('base64');
|
|
995
|
+
await adb.shell(`am broadcast -a clipper.set -e text "${base64Text}"`);
|
|
996
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
997
|
+
await adb.shell('input keyevent KEYCODE_PASTE');
|
|
998
|
+
await (0, core_utils_namespaceObject.sleep)(100);
|
|
999
|
+
debugDevice(`Clipboard input completed via clipper: "${text}"`);
|
|
1000
|
+
} catch (error2) {
|
|
1001
|
+
debugDevice(`All clipboard methods failed: ${error2}`);
|
|
1002
|
+
const isPureAscii = /^[\x00-\x7F]*$/.test(text);
|
|
1003
|
+
if (isPureAscii) {
|
|
1004
|
+
debugDevice(`Using ADB inputText for ASCII text: "${text}"`);
|
|
1005
|
+
await adb.inputText(text);
|
|
1006
|
+
} else await this.inputCharByChar(text);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async inputCharByChar(text) {
|
|
1011
|
+
const adb = await this.getAdb();
|
|
1012
|
+
debugDevice(`Inputting character by character (slow method): "${text}"`);
|
|
1013
|
+
const chars = Array.from(text);
|
|
1014
|
+
for (const char of chars){
|
|
1015
|
+
if (' ' === char) await adb.shell('input keyevent KEYCODE_SPACE');
|
|
1016
|
+
else await adb.shell(`input text "${char}"`);
|
|
1017
|
+
await (0, core_utils_namespaceObject.sleep)(50);
|
|
1018
|
+
}
|
|
1019
|
+
debugDevice("Character-by-character input completed");
|
|
966
1020
|
}
|
|
967
1021
|
async getElementsInfo() {
|
|
968
1022
|
return [];
|
|
@@ -1899,7 +1953,7 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
|
|
|
1899
1953
|
constructor(toolsManager){
|
|
1900
1954
|
super({
|
|
1901
1955
|
name: '@midscene/android-mcp',
|
|
1902
|
-
version: "1.6.
|
|
1956
|
+
version: "1.6.6",
|
|
1903
1957
|
description: 'Control the Android device using natural language commands'
|
|
1904
1958
|
}, toolsManager);
|
|
1905
1959
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -109,6 +109,16 @@ export declare class AndroidDevice implements AbstractInterface {
|
|
|
109
109
|
private resolvePackageName;
|
|
110
110
|
launch(uri: string): Promise<AndroidDevice>;
|
|
111
111
|
execYadb(keyboardContent: string): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* 通过剪贴板输入文本(备用方案,当YADB不可用时)
|
|
114
|
+
* 支持中文等非ASCII字符
|
|
115
|
+
*/
|
|
116
|
+
private inputViaClipboard;
|
|
117
|
+
/**
|
|
118
|
+
* 逐字符输入文本(最后备用方案)
|
|
119
|
+
* 通过模拟按键输入,支持中文(如果有对应输入法)
|
|
120
|
+
*/
|
|
121
|
+
private inputCharByChar;
|
|
112
122
|
getElementsInfo(): Promise<ElementInfo[]>;
|
|
113
123
|
getElementsNodeTree(): Promise<any>;
|
|
114
124
|
getScreenSize(): Promise<{
|
|
@@ -108,6 +108,16 @@ declare class AndroidDevice implements AbstractInterface {
|
|
|
108
108
|
private resolvePackageName;
|
|
109
109
|
launch(uri: string): Promise<AndroidDevice>;
|
|
110
110
|
execYadb(keyboardContent: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* 通过剪贴板输入文本(备用方案,当YADB不可用时)
|
|
113
|
+
* 支持中文等非ASCII字符
|
|
114
|
+
*/
|
|
115
|
+
private inputViaClipboard;
|
|
116
|
+
/**
|
|
117
|
+
* 逐字符输入文本(最后备用方案)
|
|
118
|
+
* 通过模拟按键输入,支持中文(如果有对应输入法)
|
|
119
|
+
*/
|
|
120
|
+
private inputCharByChar;
|
|
111
121
|
getElementsInfo(): Promise<ElementInfo[]>;
|
|
112
122
|
getElementsNodeTree(): Promise<any>;
|
|
113
123
|
getScreenSize(): Promise<{
|
package/package.json
CHANGED
package/bin/AndroidManifest.xml
DELETED
|
Binary file
|
package/bin/classes.dex
DELETED
|
Binary file
|
package/bin/resources.arsc
DELETED
|
Binary file
|