-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathpull_xapk.sh
More file actions
executable file
·127 lines (107 loc) · 4.13 KB
/
pull_xapk.sh
File metadata and controls
executable file
·127 lines (107 loc) · 4.13 KB
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/bin/bash
set -euo pipefail
# Usage: ./pull_xapk.sh <package_name> [serial]
# Examples:
# ./pull_xapk.sh uz.anormobile.retail
# ./pull_xapk.sh uz.anormobile.retail emulator-5554
# ./pull_xapk.sh com.whatsapp
if [ $# -lt 1 ]; then
echo "Usage: $0 <package_name> [adb_serial]"
echo " package_name - Android package name (e.g. com.example.app)"
echo " adb_serial - optional device serial (e.g. emulator-5554)"
exit 1
fi
PKG="$1"
ADB="adb"
if [ $# -ge 2 ]; then
ADB="adb -s $2"
fi
# Verify device is connected
if ! $ADB get-state &>/dev/null; then
echo "Error: no device connected"
[ $# -ge 2 ] && echo " Specified serial: $2"
echo " Available devices:"
adb devices -l
exit 1
fi
# Verify package exists
if ! $ADB shell pm list packages | grep -q "^package:${PKG}$"; then
echo "Error: package '$PKG' not found on device"
echo " Did you mean one of these?"
$ADB shell pm list packages | grep "${PKG%%.*}" | head -5
exit 1
fi
# Get version/SDK info from dumpsys (filter early to avoid piping megabytes through grep)
DUMPSYS=$($ADB shell "dumpsys package $PKG" | grep -E '(versionName|versionCode|minSdk|targetSdk)' | head -4)
VERSION_NAME=$(echo "$DUMPSYS" | grep -m1 'versionName' | sed 's/.*versionName=//' | tr -d '[:space:]')
VERSION_CODE=$(echo "$DUMPSYS" | grep -m1 'versionCode' | sed 's/.*versionCode=//' | awk '{print $1}' | tr -d '[:space:]')
MIN_SDK=$(echo "$DUMPSYS" | grep -m1 'minSdk' | sed 's/.*minSdk=//' | awk '{print $1}' | tr -d '[:space:]')
TARGET_SDK=$(echo "$DUMPSYS" | grep -m1 'targetSdk' | sed 's/.*targetSdk=//' | awk '{print $1}' | tr -d '[:space:]')
echo "=== Package: $PKG ==="
echo " Version: $VERSION_NAME ($VERSION_CODE)"
echo " SDK: min=$MIN_SDK target=$TARGET_SDK"
# Create output directory
OUTDIR="${PKG}_xapk"
rm -rf "$OUTDIR"
mkdir -p "$OUTDIR"
# Get all APK paths
echo ""
echo "=== Pulling APKs ==="
PATHS=$($ADB shell pm path "$PKG" | sed 's/package://' | tr -d '\r')
SPLIT_JSON=""
TOTAL_SIZE=0
for APK_PATH in $PATHS; do
FILENAME=$(basename "$APK_PATH")
echo " Pulling $FILENAME..."
$ADB pull "$APK_PATH" "$OUTDIR/$FILENAME" >/dev/null 2>&1
FILE_SIZE=$(stat -f%z "$OUTDIR/$FILENAME" 2>/dev/null || stat -c%s "$OUTDIR/$FILENAME" 2>/dev/null)
TOTAL_SIZE=$((TOTAL_SIZE + FILE_SIZE))
# Determine split id
if [ "$FILENAME" = "base.apk" ]; then
SPLIT_ID="base"
else
SPLIT_ID=$(echo "$FILENAME" | sed 's/\.apk$//' | sed 's/^split_//')
fi
SPLIT_JSON="${SPLIT_JSON}{\"file\":\"${FILENAME}\",\"id\":\"${SPLIT_ID}\"},"
done
# Remove trailing comma
SPLIT_JSON="${SPLIT_JSON%,}"
NUM_APKS=$(echo "$PATHS" | wc -l | tr -d ' ')
echo " Pulled $NUM_APKS APK(s), total size: $((TOTAL_SIZE / 1024 / 1024)) MB"
# Extract human-readable app name from the pulled base.apk using aapt2/aapt
APP_NAME=""
if [ -f "$OUTDIR/base.apk" ]; then
if command -v aapt2 &>/dev/null; then
APP_NAME=$(aapt2 dump badging "$OUTDIR/base.apk" 2>/dev/null | grep "^application-label:" | head -1 | sed "s/application-label:'//;s/'$//")
elif command -v aapt &>/dev/null; then
APP_NAME=$(aapt dump badging "$OUTDIR/base.apk" 2>/dev/null | grep "^application-label:" | head -1 | sed "s/application-label:'//;s/'$//")
fi
fi
[ -z "$APP_NAME" ] && APP_NAME="$PKG"
echo " App name: $APP_NAME"
# Create manifest.json
echo ""
echo "=== Building XAPK ==="
cat > "$OUTDIR/manifest.json" << MANIFEST
{
"xapk_version": 2,
"package_name": "$PKG",
"name": "$APP_NAME",
"version_code": "$VERSION_CODE",
"version_name": "$VERSION_NAME",
"min_sdk_version": "$MIN_SDK",
"target_sdk_version": "$TARGET_SDK",
"total_size": $TOTAL_SIZE,
"split_apks": [$SPLIT_JSON]
}
MANIFEST
# Build XAPK (zip with no compression — APKs are already compressed)
XAPK_FILE="${PKG}_v${VERSION_NAME}.xapk"
(cd "$OUTDIR" && zip -0 -q "../$XAPK_FILE" manifest.json *.apk)
XAPK_SIZE=$(stat -f%z "$XAPK_FILE" 2>/dev/null || stat -c%s "$XAPK_FILE" 2>/dev/null)
echo " Created: $XAPK_FILE ($((XAPK_SIZE / 1024 / 1024)) MB)"
echo ""
echo "=== Contents ==="
unzip -l "$XAPK_FILE" | grep -E '(apk|json)' | awk '{printf " %-45s %s\n", $4, $1}'
echo ""
echo "Done. Output: $XAPK_FILE"