| name | launch-on-device |
| description | Build, install, and launch the Zhihu++ Android app on a connected device using ADB. Includes comprehensive troubleshooting for common issues like missing devices, installation failures, signature mismatches, and app crashes. Use when deploying debug builds to physical devices or emulators. |
| license | CC BY-NC-SA 4.0 |
Launch on Device Skill
Overview
This skill documents how to build, install, and launch the Zhihu++ Android app on a connected device using ADB (Android Debug Bridge).
Prerequisites
- ADB installed and available in PATH
- Android device connected via USB or wireless ADB
- USB debugging enabled on device
- Project built successfully
Quick Start
./gradlew assembleLiteDebug
adb install -r ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
adb shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Detailed Workflow
Step 1: Check ADB Connection
which adb
adb --version
adb devices
Expected output:
List of devices attached
<device-id> device
Step 2: Build the APK
cd /path/to/Zhihu
./gradlew assembleLiteDebug --quiet
The APK will be generated at: ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
Step 3: Install APK to Device
adb install -r ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
Expected output: Success
Step 4: Launch the App
adb shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Expected output: Starting: Intent { cmp=com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity }
Login JSON Backup and Restore
When Android or JVM verification is blocked by repeated login, first try restoring the saved account JSON instead of logging in again.
Account JSON Handling Policy
Account JSON is runtime state, not a Gradle input. Do not add Gradle tasks, generated source sets, androidTest assets, or any other build-script wiring that copies .secret/account.json or another account JSON into the app or test APK.
Agents must restore account JSON manually before UI checks or real-data instrumented tests. Use adb push plus run-as to copy the chosen backup into the target app sandbox as files/account.json, then launch or run instrumentation.
Backup After a Successful Android Login
mkdir -p ~/.zhihu-plus-plus/backups
adb exec-out run-as com.github.zly2006.zhplus.lite cat files/account.json \
> ~/.zhihu-plus-plus/backups/android-lite-account-$(date +%Y%m%d-%H%M%S).json
python3 - <<'PY'
import json, pathlib
p = max(pathlib.Path.home().joinpath(".zhihu-plus-plus/backups").glob("android-lite-account-*.json"))
data = json.loads(p.read_text())
print("valid_json=true")
print("login=", data.get("login"))
print("has_z_c0=", "z_c0" in data.get("cookies", {}))
print("has_d_c0=", "d_c0" in data.get("cookies", {}))
PY
Do not print cookie values. Only verify that the JSON parses and contains the required keys.
Restore Android Login State
BACKUP=~/.zhihu-plus-plus/backups/android-lite-account-YYYYMMDD-HHMMSS.json
adb push "$BACKUP" /data/local/tmp/zhihu-account.json
adb shell run-as com.github.zly2006.zhplus.lite sh -c 'cp /data/local/tmp/zhihu-account.json files/account.json && chmod 600 files/account.json'
adb shell am force-stop com.github.zly2006.zhplus.lite
adb shell monkey -p com.github.zly2006.zhplus.lite -c android.intent.category.LAUNCHER 1
If the only available source is the project-local secret file, copy it manually in the same way:
BACKUP=.secret/account.json
adb push "$BACKUP" /data/local/tmp/zhihu-account.json
adb shell run-as com.github.zly2006.zhplus.lite sh -c 'cp /data/local/tmp/zhihu-account.json files/account.json && chmod 600 files/account.json'
For real-data instrumented tests, restore files/account.json first, then pass zhpp_data_mode=real:
adb shell am instrument -w \
-e zhpp_data_mode real \
com.github.zly2006.zhplus.lite.test/com.github.zly2006.zhihu.ZhihuInstrumentedTestRunner
Reuse Android Login for JVM/Desktop
The JVM desktop account store is ~/.zhihu-plus-plus/account.json. If the desktop app keeps asking for QR login while Android is already logged in, back up the old desktop file and copy the latest Android backup over it:
cp ~/.zhihu-plus-plus/account.json ~/.zhihu-plus-plus/backups/desktop-account-before-android-sync-$(date +%Y%m%d-%H%M%S).json 2>/dev/null || true
cp ~/.zhihu-plus-plus/backups/android-lite-account-YYYYMMDD-HHMMSS.json ~/.zhihu-plus-plus/account.json
If a fresh JVM QR login is still necessary, notify the user before waiting:
terminal-notifier -message "需要扫码登录 JVM 端" -sound default
App Variants
The project has two build variants:
-
Lite Version (recommended for development)
- Package:
com.github.zly2006.zhplus.lite
- APK:
./app/build/outputs/apk/lite/debug/app-lite-debug.apk
- Main Activity:
com.github.zly2006.zhihu.MainActivity
-
Full Version
- Package:
com.github.zly2006.zhplus
- APK:
./app/build/outputs/apk/full/debug/app-full-debug.apk
- Main Activity:
com.github.zly2006.zhihu.MainActivity
Common Issues and Solutions
Issue 1: ADB Server Not Running
Symptom:
error: could not connect to daemon
Solution:
adb kill-server
adb start-server
adb devices
Issue 2: No Devices Connected
Symptom:
List of devices attached
(empty list)
Solutions:
a) USB Connection Issues:
b) Unauthorized Device:
adb devices
c) Wireless ADB Connection:
adb connect <device-ip>:5555
Issue 3: APK Not Found
Symptom:
adb: failed to stat ./app/build/outputs/apk/lite/debug/app-lite-debug.apk: No such file or directory
Solution:
./gradlew assembleLiteDebug
ls -lh ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
./gradlew clean assembleLiteDebug
Issue 4: Installation Failed (INSTALL_FAILED_UPDATE_INCOMPATIBLE)
Symptom:
Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package com.github.zly2006.zhplus.lite signatures do not match newer version]
Solution:
adb uninstall com.github.zly2006.zhplus.lite
adb install ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
Issue 5: Installation Failed (Insufficient Storage)
Symptom:
Failure [INSTALL_FAILED_INSUFFICIENT_STORAGE]
Solution:
adb shell df -h
adb shell pm list packages | grep -i <package-pattern>
adb uninstall <package-name>
Issue 6: Multiple Devices Connected
Symptom:
error: more than one device/emulator
Solution:
adb devices
adb -s <device-id> install -r ./app/build/outputs/apk/lite/debug/app-lite-debug.apk
adb -s <device-id> shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Issue 7: App Crashes on Launch
Symptom:
App installs but crashes immediately after launch.
Solution:
adb logcat | grep -i "AndroidRuntime\|FATAL\|zhplus"
adb logcat --pid=$(adb shell pidof -s com.github.zly2006.zhplus.lite)
adb shell pm clear com.github.zly2006.zhplus.lite
adb shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Issue 8: Activity Not Found
Symptom:
Error: Activity class {...} does not exist.
Solution:
adb shell pm list packages | grep zhplus
adb shell dumpsys package com.github.zly2006.zhplus.lite | grep -A 1 "android.intent.action.MAIN:"
adb shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Useful ADB Commands
App Management
adb shell pm list packages | grep zhplus
adb shell pm path com.github.zly2006.zhplus.lite
adb shell pm clear com.github.zly2006.zhplus.lite
adb uninstall com.github.zly2006.zhplus.lite
adb shell am force-stop com.github.zly2006.zhplus.lite
adb shell dumpsys package com.github.zly2006.zhplus.lite
Device Information
adb shell getprop ro.build.version.release
adb shell getprop ro.product.model
adb shell getprop ro.product.manufacturer
adb shell df -h
adb shell dumpsys battery
adb exec-out screencap -p > screenshot.png
Debugging
adb logcat
adb logcat -s TAG_NAME
adb logcat --pid=$(adb shell pidof -s com.github.zly2006.zhplus.lite)
adb logcat -d > logcat.txt
adb logcat -c
Complete One-Line Command
For quick deployment after code changes:
./gradlew assembleLiteDebug && adb install -r ./app/build/outputs/apk/lite/debug/app-lite-debug.apk && adb shell am start -n com.github.zly2006.zhplus.lite/com.github.zly2006.zhihu.MainActivity
Advanced: Automatic Build and Deploy Script
Create a script deploy.sh:
#!/bin/bash
set -e
echo "🔨 Building lite debug APK..."
./gradlew assembleLiteDebug --quiet
APK_PATH="./app/build/outputs/apk/lite/debug/app-lite-debug.apk"
PACKAGE_NAME="com.github.zly2006.zhplus.lite"
ACTIVITY="com.github.zly2006.zhihu.MainActivity"
if [ ! -f "$APK_PATH" ]; then
echo "❌ APK not found at $APK_PATH"
exit 1
fi
echo "📱 Checking device connection..."
DEVICE_COUNT=$(adb devices | grep -w "device" | wc -l)
if [ "$DEVICE_COUNT" -eq 0 ]; then
echo "❌ No devices connected"
echo "Please connect a device and enable USB debugging"
exit 1
fi
if [ "$DEVICE_COUNT" -gt 1 ]; then
echo "⚠️ Multiple devices connected:"
adb devices
echo "Please specify device with: adb -s <device-id>"
exit 1
fi
echo "📦 Installing APK..."
if adb install -r "$APK_PATH" 2>&1 | grep -q "Success"; then
echo "✅ Installation successful"
else
echo "⚠️ Installation failed, trying to uninstall first..."
adb uninstall "$PACKAGE_NAME" 2>/dev/null || true
if adb install "$APK_PATH" 2>&1 | grep -q "Success"; then
echo "✅ Installation successful after uninstall"
else
echo "❌ Installation failed"
exit 1
fi
fi
echo "🚀 Launching app..."
adb shell am start -n "$PACKAGE_NAME/$ACTIVITY"
echo "✨ Done! App should be launching on your device."
Make it executable:
chmod +x deploy.sh
./deploy.sh
Troubleshooting Checklist
When things don't work, check these in order:
- ✅ Is ADB installed? →
which adb
- ✅ Is ADB server running? →
adb devices
- ✅ Is device connected? → Should show
device status
- ✅ Is USB debugging enabled on device?
- ✅ Is USB debugging authorized? → Accept prompt on device
- ✅ Is APK built? → Check
./app/build/outputs/apk/lite/debug/
- ✅ Is package name correct? →
com.github.zly2006.zhplus.lite
- ✅ Is activity name correct? →
com.github.zly2006.zhihu.MainActivity
- ✅ Check logs for errors →
adb logcat
References
Last Updated: 2026-02-03
Tested with: ADB 1.0.41, Android SDK Platform Tools 36.0.2