@skrillex1224/android-toolkit 1.0.9 → 1.0.10

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/dist/index.cjs CHANGED
@@ -282,7 +282,7 @@ function safeJson(value) {
282
282
 
283
283
  // src/device.js
284
284
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
285
- var Device = {
285
+ var Device2 = {
286
286
  adbExec,
287
287
  adbShell,
288
288
  forceStopApp,
@@ -663,7 +663,7 @@ function createApifyKit(options = {}) {
663
663
  if (failActor) {
664
664
  let base64 = "";
665
665
  try {
666
- base64 = await Device.screenshotBase64(ctx);
666
+ base64 = await Device2.screenshotBase64(ctx);
667
667
  } catch (error) {
668
668
  base64 = `\u622A\u56FE\u5931\u8D25: ${error?.message || String(error)}`;
669
669
  }
@@ -781,7 +781,7 @@ var DeviceView = {
781
781
  normalizeSelector
782
782
  };
783
783
  async function snapshot(ctx, options = {}) {
784
- const xml = options.xml || await Device.dumpUiXml(ctx);
784
+ const xml = options.xml || await Device2.dumpUiXml(ctx);
785
785
  const parsed = parser.parse(xml);
786
786
  const roots = toArray(parsed?.hierarchy?.node).map((node) => normalizeNode(node, null, 0));
787
787
  const flat = [];
@@ -965,6 +965,12 @@ function selectorLabel(selector) {
965
965
  }
966
966
 
967
967
  // src/device-input.js
968
+ var SCROLL_MAX_SWIPES = 24;
969
+ var SCROLL_STABLE_ROUNDS = 1;
970
+ var SCROLL_SWIPE_RATIO = 0.72;
971
+ var SCROLL_DURATION_MS = 360;
972
+ var SCROLL_SETTLE_MS = 500;
973
+ var SCROLL_HASH_SOURCE = "screenshot";
968
974
  var DeviceInput = {
969
975
  click,
970
976
  tap: click,
@@ -978,12 +984,12 @@ var DeviceInput = {
978
984
  };
979
985
  async function click(ctx, selectorOrPoint, options = {}) {
980
986
  if (isPoint(selectorOrPoint)) {
981
- await Device.tapAbsolute(ctx, selectorOrPoint.x, selectorOrPoint.y);
987
+ await Device2.tapAbsolute(ctx, selectorOrPoint.x, selectorOrPoint.y);
982
988
  return { point: selectorOrPoint };
983
989
  }
984
990
  if (isBounds(selectorOrPoint)) {
985
991
  const point2 = centerOf(selectorOrPoint);
986
- await Device.tapAbsolute(ctx, point2.x, point2.y);
992
+ await Device2.tapAbsolute(ctx, point2.x, point2.y);
987
993
  return { point: point2 };
988
994
  }
989
995
  const target = await DeviceView.find(ctx, selectorOrPoint, options);
@@ -1002,7 +1008,7 @@ async function click(ctx, selectorOrPoint, options = {}) {
1002
1008
  actual: simplifyNode(actual),
1003
1009
  point
1004
1010
  });
1005
- await Device.tapAbsolute(ctx, point.x, point.y);
1011
+ await Device2.tapAbsolute(ctx, point.x, point.y);
1006
1012
  await sleep(Number(options.settleMs || 250));
1007
1013
  return { target, actual, point };
1008
1014
  }
@@ -1013,7 +1019,7 @@ async function fill(ctx, selector, text2, options = {}) {
1013
1019
  settleMs: Number(options.focusSettleMs || 350)
1014
1020
  });
1015
1021
  try {
1016
- await Device.typeText(ctx, value);
1022
+ await Device2.typeText(ctx, value);
1017
1023
  } catch (error) {
1018
1024
  throw new CrawlerError({
1019
1025
  message: `automation_failed: View \u5199\u5165\u6587\u672C\u5931\u8D25 ${JSON.stringify(selector)}`,
@@ -1030,10 +1036,10 @@ async function fill(ctx, selector, text2, options = {}) {
1030
1036
  return { target: clicked.actual || clicked.target, chars: value.length };
1031
1037
  }
1032
1038
  async function press(ctx, key) {
1033
- await Device.pressKey(ctx, key);
1039
+ await Device2.pressKey(ctx, key);
1034
1040
  }
1035
1041
  async function pressEnter2(ctx) {
1036
- await Device.pressEnter(ctx);
1042
+ await Device2.pressEnter(ctx);
1037
1043
  }
1038
1044
  async function scroll(ctx, selector, direction, options = {}) {
1039
1045
  const node = await DeviceView.find(ctx, selector, options);
@@ -1041,8 +1047,8 @@ async function scroll(ctx, selector, direction, options = {}) {
1041
1047
  }
1042
1048
  async function scrollBounds(ctx, bounds2, direction, options = {}) {
1043
1049
  const box = bounds2;
1044
- const ratio = Number(options.swipeRatio || 0.72);
1045
- const durationMs = Number(options.durationMs || 360);
1050
+ const ratio = Number(options.swipeRatio || SCROLL_SWIPE_RATIO);
1051
+ const durationMs = Number(options.durationMs || SCROLL_DURATION_MS);
1046
1052
  const x = box.centerX;
1047
1053
  const distance = Math.max(40, box.height * ratio);
1048
1054
  const down = String(direction || "").toLowerCase() === "down";
@@ -1054,8 +1060,8 @@ async function scrollBounds(ctx, bounds2, direction, options = {}) {
1054
1060
  x,
1055
1061
  y: down ? Math.min(box.bottom - 10, from.y + distance) : Math.max(box.top + 10, from.y - distance)
1056
1062
  };
1057
- await Device.swipe(ctx, from, to, durationMs);
1058
- await sleep(Number(options.settleMs || 500));
1063
+ await Device2.swipe(ctx, from, to, durationMs);
1064
+ await sleep(Number(options.settleMs || SCROLL_SETTLE_MS));
1059
1065
  }
1060
1066
  async function scrollToEnd(ctx, selector, options = {}) {
1061
1067
  return scrollUntilStable(ctx, selector, "up", options);
@@ -1064,56 +1070,30 @@ async function scrollToTop(ctx, selector, options = {}) {
1064
1070
  return scrollUntilStable(ctx, selector, "down", options);
1065
1071
  }
1066
1072
  async function scrollUntilStable(ctx, selector, direction, options = {}) {
1067
- const maxSwipes = Math.max(1, Number(options.maxSwipes || 20));
1068
- const stableRoundsTarget = Math.max(1, Number(options.stableRounds || 2));
1069
- const hashSource = String(options.stability || options.hashSource || "view");
1070
- if (hashSource === "screenshot") {
1071
- return scrollUntilScreenshotStable(ctx, selector, direction, options, maxSwipes, stableRoundsTarget, hashSource);
1072
- }
1073
- let lastHash = "";
1074
- let stableRounds = 0;
1075
- for (let index = 0; index < maxSwipes; index += 1) {
1076
- const currentHash = await scrollStateHash(ctx, selector, options, hashSource);
1077
- if (currentHash === lastHash) {
1078
- stableRounds += 1;
1079
- if (stableRounds >= stableRoundsTarget) {
1080
- return { swipes: index, stableRounds, hash: currentHash, hashSource, capped: false };
1081
- }
1082
- } else {
1083
- stableRounds = 0;
1084
- lastHash = currentHash;
1085
- }
1086
- await scroll(ctx, selector, direction, options);
1087
- }
1088
- return { swipes: maxSwipes, stableRounds, hash: lastHash, hashSource, capped: true };
1089
- }
1090
- async function scrollUntilScreenshotStable(ctx, selector, direction, options, maxSwipes, stableRoundsTarget, hashSource) {
1073
+ const maxSwipes = Math.max(1, Number(options.maxSwipes || SCROLL_MAX_SWIPES));
1074
+ const stableRoundsTarget = Math.max(1, Number(options.stableRounds || SCROLL_STABLE_ROUNDS));
1091
1075
  const node = await DeviceView.find(ctx, selector, options);
1092
1076
  const bounds2 = node.bounds;
1093
- let lastHash = await scrollStateHash(ctx, selector, options, hashSource);
1077
+ let lastHash = await scrollStateHash(ctx);
1094
1078
  let stableRounds = 0;
1095
1079
  for (let index = 0; index < maxSwipes; index += 1) {
1096
1080
  await scrollBounds(ctx, bounds2, direction, options);
1097
- const currentHash = await scrollStateHash(ctx, selector, options, hashSource);
1081
+ const currentHash = await scrollStateHash(ctx);
1098
1082
  if (currentHash === lastHash) {
1099
1083
  stableRounds += 1;
1100
1084
  if (stableRounds >= stableRoundsTarget) {
1101
- return { swipes: index + 1, stableRounds, hash: currentHash, hashSource, capped: false };
1085
+ return { swipes: index + 1, stableRounds, hash: currentHash, hashSource: SCROLL_HASH_SOURCE, capped: false };
1102
1086
  }
1103
1087
  } else {
1104
1088
  stableRounds = 0;
1105
1089
  lastHash = currentHash;
1106
1090
  }
1107
1091
  }
1108
- return { swipes: maxSwipes, stableRounds, hash: lastHash, hashSource, capped: true };
1092
+ return { swipes: maxSwipes, stableRounds, hash: lastHash, hashSource: SCROLL_HASH_SOURCE, capped: true };
1109
1093
  }
1110
- async function scrollStateHash(ctx, selector, options, hashSource) {
1111
- if (hashSource === "screenshot") {
1112
- const png = await Device.screenshotPng(ctx);
1113
- return (0, import_node_crypto2.createHash)("sha256").update(png).digest("hex");
1114
- }
1115
- const node = await DeviceView.find(ctx, selector, options);
1116
- return DeviceView.hashNode(node);
1094
+ async function scrollStateHash(ctx) {
1095
+ const png = await Device2.screenshotPng(ctx);
1096
+ return (0, import_node_crypto2.createHash)("sha256").update(png).digest("hex");
1117
1097
  }
1118
1098
  function nearestClickable(node) {
1119
1099
  let current = node;
@@ -1280,7 +1260,7 @@ async function pullDatabaseSnapshot(ctx, dbPath, localDir) {
1280
1260
  }
1281
1261
  }
1282
1262
  async function adbSuShell(ctx, command, options = {}) {
1283
- return Device.adbShell(ctx, [`su -c ${shellQuote(command)}`], options);
1263
+ return Device2.adbShell(ctx, [`su -c ${shellQuote(command)}`], options);
1284
1264
  }
1285
1265
  async function queryLocalSQLite(dbPath, config) {
1286
1266
  const payloadPath = `${dbPath}.query.json`;
@@ -1717,6 +1697,11 @@ var DEFAULT_COLUMNS = 3;
1717
1697
  var DEFAULT_SETTLE_MS = 550;
1718
1698
  var DEFAULT_TIMEOUT_MS = 5e4;
1719
1699
  var DEFAULT_POLL_INTERVAL_MS = 800;
1700
+ var RESET_TO_TOP_MAX_SWIPES = 16;
1701
+ var RESET_TO_TOP_STABLE_ROUNDS = 1;
1702
+ var CAPTURE_SCROLL_STEP_RATIO = 0.56;
1703
+ var CAPTURE_SCROLL_DURATION_MS = 360;
1704
+ var SPRITE_GAP = 16;
1720
1705
  var Share = {
1721
1706
  captureScreen,
1722
1707
  captureLink
@@ -1726,15 +1711,13 @@ async function captureScreen(ctx, options = {}) {
1726
1711
  const frameBuffers = [];
1727
1712
  const seen = /* @__PURE__ */ new Set();
1728
1713
  const targetSelector = options.selector || { id: "message_list" };
1729
- const shouldHideKeyboard = options.hideKeyboard !== false;
1730
- if (shouldHideKeyboard) await Device.hideKeyboard(ctx, { attempts: 2, settleMs: 350 }).catch(() => {
1731
- });
1732
- try {
1733
- const topResult = await DeviceInput.scrollToTop(ctx, targetSelector, {
1734
- maxSwipes: Number(options.scrollToTopMaxSwipes || 12),
1735
- stableRounds: Number(options.scrollToTopStableRounds || 2),
1736
- settleMs: 400,
1737
- stability: options.scrollStability || options.stability || "view"
1714
+ const resetToTop = options.resetToTop !== false;
1715
+ let topResult = null;
1716
+ if (resetToTop) {
1717
+ topResult = await DeviceInput.scrollToTop(ctx, targetSelector, {
1718
+ maxSwipes: RESET_TO_TOP_MAX_SWIPES,
1719
+ stableRounds: RESET_TO_TOP_STABLE_ROUNDS,
1720
+ settleMs: 400
1738
1721
  });
1739
1722
  Logger.info("captureScreen scrollToTop", {
1740
1723
  swipes: topResult?.swipes,
@@ -1742,13 +1725,20 @@ async function captureScreen(ctx, options = {}) {
1742
1725
  hashSource: topResult?.hashSource,
1743
1726
  capped: topResult?.capped === true
1744
1727
  });
1745
- } catch (error) {
1746
- if (options.strictScrollToTop === true) throw error;
1747
- Logger.warn("captureScreen scrollToTop skipped", { message: error?.message || String(error) });
1728
+ if (topResult?.capped === true) {
1729
+ throw new CrawlerError({
1730
+ message: `source_extraction_failed: \u622A\u56FE\u524D\u672A\u80FD\u786E\u8BA4\u56DE\u5230\u9876\u90E8 swipes=${topResult.swipes} stableRounds=${topResult.stableRounds}`,
1731
+ code: Code.SourceExtractionFailed,
1732
+ context: {
1733
+ selector: targetSelector,
1734
+ swipes: topResult.swipes,
1735
+ stableRounds: topResult.stableRounds,
1736
+ hashSource: topResult.hashSource
1737
+ }
1738
+ });
1739
+ }
1748
1740
  }
1749
1741
  for (let index = 0; index < DEFAULT_CAPTURE_COUNT; index += 1) {
1750
- if (shouldHideKeyboard) await Device.hideKeyboard(ctx, { attempts: 1, settleMs: 250 }).catch(() => {
1751
- });
1752
1742
  await sleep(DEFAULT_SETTLE_MS);
1753
1743
  const png = await Device.screenshotPng(ctx);
1754
1744
  const hash = (0, import_node_crypto3.createHash)("sha256").update(png).digest("hex");
@@ -1757,18 +1747,21 @@ async function captureScreen(ctx, options = {}) {
1757
1747
  frameBuffers.push(png);
1758
1748
  if (index >= DEFAULT_CAPTURE_COUNT - 1) break;
1759
1749
  await DeviceInput.scroll(ctx, targetSelector, "up", {
1760
- swipeRatio: 0.72,
1761
- durationMs: 360,
1750
+ swipeRatio: CAPTURE_SCROLL_STEP_RATIO,
1751
+ durationMs: CAPTURE_SCROLL_DURATION_MS,
1762
1752
  settleMs: DEFAULT_SETTLE_MS
1763
1753
  }).catch(() => {
1764
1754
  });
1765
1755
  }
1766
- const sprite = await composeSprite(frameBuffers, { columns: DEFAULT_COLUMNS, gap: 16 });
1756
+ const sprite = await composeSprite(frameBuffers, { columns: DEFAULT_COLUMNS, gap: SPRITE_GAP });
1767
1757
  const compression = resolveImageCompression(options);
1768
1758
  const base64 = await compressImageBufferToBase64(sprite, compression);
1769
1759
  Logger.success("Share.captureScreen", {
1770
1760
  duration: Logger.duration(startedAt),
1771
1761
  frameCount: frameBuffers.length,
1762
+ scrollStepRatio: CAPTURE_SCROLL_STEP_RATIO,
1763
+ resetToTop,
1764
+ topCapped: topResult?.capped === true,
1772
1765
  base64Bytes: Math.ceil(base64.length)
1773
1766
  });
1774
1767
  return `data:image/jpeg;base64,${base64}`;
@@ -1783,7 +1776,6 @@ async function captureLink(ctx, options = {}) {
1783
1776
  });
1784
1777
  }
1785
1778
  const timeoutMs = Number(options.timeoutMs || DEFAULT_TIMEOUT_MS);
1786
- const pollIntervalMs = Number(options.pollIntervalMs || DEFAULT_POLL_INTERVAL_MS);
1787
1779
  const deadline = Date.now() + timeoutMs;
1788
1780
  const prefix = String(share.prefix || "").trim();
1789
1781
  Logger.start("Share.captureLink", { actor: actorInfo.key, prefix, timeoutMs });
@@ -1805,7 +1797,7 @@ async function captureLink(ctx, options = {}) {
1805
1797
  if (link && link === beforeLink) {
1806
1798
  lastEvent = { ...event, rejected: "same_as_baseline", beforeLink };
1807
1799
  }
1808
- await sleep(pollIntervalMs);
1800
+ await sleep(DEFAULT_POLL_INTERVAL_MS);
1809
1801
  }
1810
1802
  throw new CrawlerError({
1811
1803
  message: "source_extraction_failed: \u672A\u6355\u83B7\u5206\u4EAB\u94FE\u63A5",
@@ -1901,7 +1893,7 @@ async function run(handler, options = {}) {
1901
1893
  const kit = {
1902
1894
  Launch,
1903
1895
  ApifyKit: apifyKit,
1904
- Device,
1896
+ Device: Device2,
1905
1897
  DeviceInput,
1906
1898
  DeviceView,
1907
1899
  DeviceSQLite,
@@ -1952,7 +1944,7 @@ var useAndroidToolKit = () => {
1952
1944
  DeviceInput,
1953
1945
  DeviceView,
1954
1946
  DeviceSQLite,
1955
- Device,
1947
+ Device: Device2,
1956
1948
  Mutation,
1957
1949
  Share,
1958
1950
  Constants: constants_exports,