@aiscene/android 1.6.3 → 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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/lib/cli.js');
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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1413,8 +1467,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1413
1467
  if (!this.yadbPushed) {
1414
1468
  const adb = await this.getAdb();
1415
1469
  const androidPkgJson = (0, external_node_module_.createRequire)(import.meta.url).resolve('@aiscene/android/package.json');
1416
- const yadbBin = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin', 'yadb');
1417
- await adb.push(yadbBin, '/data/local/tmp');
1470
+ const yadbDir = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin');
1471
+ await adb.push(yadbDir, '/data/local/tmp');
1418
1472
  this.yadbPushed = true;
1419
1473
  }
1420
1474
  }
@@ -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.3"
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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1316,8 +1370,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1316
1370
  if (!this.yadbPushed) {
1317
1371
  const adb = await this.getAdb();
1318
1372
  const androidPkgJson = (0, external_node_module_.createRequire)(import.meta.url).resolve('@aiscene/android/package.json');
1319
- const yadbBin = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin', 'yadb');
1320
- await adb.push(yadbBin, '/data/local/tmp');
1373
+ const yadbDir = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin');
1374
+ await adb.push(yadbDir, '/data/local/tmp');
1321
1375
  this.yadbPushed = true;
1322
1376
  }
1323
1377
  }
@@ -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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1412,8 +1466,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1412
1466
  if (!this.yadbPushed) {
1413
1467
  const adb = await this.getAdb();
1414
1468
  const androidPkgJson = (0, external_node_module_.createRequire)(import.meta.url).resolve('@aiscene/android/package.json');
1415
- const yadbBin = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin', 'yadb');
1416
- await adb.push(yadbBin, '/data/local/tmp');
1469
+ const yadbDir = external_node_path_["default"].join(external_node_path_["default"].dirname(androidPkgJson), 'bin');
1470
+ await adb.push(yadbDir, '/data/local/tmp');
1417
1471
  this.yadbPushed = true;
1418
1472
  }
1419
1473
  }
@@ -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.3",
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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1428,8 +1482,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1428
1482
  if (!this.yadbPushed) {
1429
1483
  const adb = await this.getAdb();
1430
1484
  const androidPkgJson = (0, external_node_module_.createRequire)(__rslib_import_meta_url__).resolve('@aiscene/android/package.json');
1431
- const yadbBin = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin', 'yadb');
1432
- await adb.push(yadbBin, '/data/local/tmp');
1485
+ const yadbDir = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin');
1486
+ await adb.push(yadbDir, '/data/local/tmp');
1433
1487
  this.yadbPushed = true;
1434
1488
  }
1435
1489
  }
@@ -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.3"
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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1349,8 +1403,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1349
1403
  if (!this.yadbPushed) {
1350
1404
  const adb = await this.getAdb();
1351
1405
  const androidPkgJson = (0, external_node_module_.createRequire)(__rslib_import_meta_url__).resolve('@aiscene/android/package.json');
1352
- const yadbBin = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin', 'yadb');
1353
- await adb.push(yadbBin, '/data/local/tmp');
1406
+ const yadbDir = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin');
1407
+ await adb.push(yadbDir, '/data/local/tmp');
1354
1408
  this.yadbPushed = true;
1355
1409
  }
1356
1410
  }
@@ -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
- await adb.shell(`app_process${this.getDisplayArg()} -Djava.class.path=/data/local/tmp/yadb /data/local/tmp com.ysbing.yadb.Main -keyboard "${keyboardContent}"`);
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 [];
@@ -1443,8 +1497,8 @@ ${Object.keys(size).filter((key)=>size[key]).map((key)=>` ${key} size: ${size[k
1443
1497
  if (!this.yadbPushed) {
1444
1498
  const adb = await this.getAdb();
1445
1499
  const androidPkgJson = (0, external_node_module_.createRequire)(__rslib_import_meta_url__).resolve('@aiscene/android/package.json');
1446
- const yadbBin = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin', 'yadb');
1447
- await adb.push(yadbBin, '/data/local/tmp');
1500
+ const yadbDir = external_node_path_default().join(external_node_path_default().dirname(androidPkgJson), 'bin');
1501
+ await adb.push(yadbDir, '/data/local/tmp');
1448
1502
  this.yadbPushed = true;
1449
1503
  }
1450
1504
  }
@@ -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.3",
1956
+ version: "1.6.6",
1903
1957
  description: 'Control the Android device using natural language commands'
1904
1958
  }, toolsManager);
1905
1959
  }
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiscene/android",
3
- "version": "1.6.3",
3
+ "version": "1.6.6",
4
4
  "description": "Android automation library for Midscene",
5
5
  "keywords": [
6
6
  "Android UI automation",
Binary file
@@ -1,2 +0,0 @@
1
- appMetadataVersion=1.1
2
- androidGradlePluginVersion=7.4.2
package/bin/classes.dex DELETED
Binary file
Binary file