Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ jobs:
"os": "ubuntu-latest",
"release": "android",
"rust_target": "aarch64-linux-android,armv7-linux-androideabi,i686-linux-android,x86_64-linux-android",
"manual": false
"manual": true
},
{
"os": "ubuntu-22.04",
Expand Down Expand Up @@ -279,7 +279,17 @@ jobs:
cd app/
rm -rf src-tauri/gen/android
pnpm tauri android init
pnpm tauri icon ../../data/icons/myreader-book.png
# gen/android is gitignored (never committed), so `tauri android
# init` always regenerates a vanilla app/build.gradle.kts that
# doesn't know about tauri-plugin-native-bridge's foss/googleplay
# `store` product flavor (see plugins/tauri-plugin-native-bridge/
# android/build.gradle.kts). Without a strategy Gradle can't pick
# between the two variants and fails with a "cannot choose between
# fossReleaseRuntimeElements and googleplayReleaseRuntimeElements"
# dependency resolution error. Re-inject the same fix documented
# in README.md's local Android setup steps on every fresh init.
sed -i '/defaultConfig {/a\ missingDimensionStrategy("store", "foss", "googleplay")' src-tauri/gen/android/app/build.gradle.kts
pnpm tauri icon ../data/icons/myreader-book.png
git checkout .

pushd src-tauri/gen/android
Expand All @@ -288,15 +298,39 @@ jobs:
base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties

# `tauri android init` regenerates app/build.gradle.kts from a
# vanilla template with no signingConfigs block at all, so
# keystore.properties above was written but never read: every
# release build was silently *unsigned*
# (app-universal-release-unsigned.apk), which then fails to
# install with INSTALL_PARSE_FAILED_NO_CERTIFICATES even though
# the ANDROID_KEY_* secrets were set correctly. Wire the release
# build type to a signingConfig sourced from keystore.properties
# on every fresh init.
# NOTE: use the bare `Properties()` (already imported at the top of
# build.gradle.kts) rather than `java.util.Properties()` here — AGP's
# `android {}` extension exposes its own `java { ... }` toolchain DSL
# accessor that shadows the top-level `java` package inside this
# scope, so the fully-qualified form fails with
# "Unresolved reference: util".
perl -0777 -pi -e 's/android \{\r?\n/android {\n signingConfigs {\n create("release") {\n val keystorePropertiesFile = rootProject.file("keystore.properties")\n if (keystorePropertiesFile.exists()) {\n val keystoreProperties = Properties()\n keystoreProperties.load(keystorePropertiesFile.inputStream())\n keyAlias = keystoreProperties.getProperty("keyAlias")\n keyPassword = keystoreProperties.getProperty("password")\n storeFile = file(keystoreProperties.getProperty("storeFile"))\n storePassword = keystoreProperties.getProperty("password")\n }\n }\n }\n/' app/build.gradle.kts
sed -i '/getByName("release") {/a\ signingConfig = signingConfigs.getByName("release")' app/build.gradle.kts

popd
version=${{ needs.get-release.outputs.release_version }}
apk_path=src-tauri/gen/android/app/build/outputs/apk/universal/release
universial_apk=MyReader_${version}_universal.apk
arm64_apk=MyReader_${version}_arm64.apk
# Now that signingConfig is wired above, release builds produce
# app-universal-release.apk (signed). Still pick the newest
# matching file rather than hardcoding the name, as a safety net
# in case signing silently falls through (e.g. a missing secret
# leaves keystorePropertiesFile.exists() false) and gradle falls
# back to the -unsigned.apk name.
pnpm tauri android build
cp ${apk_path}/app-universal-release.apk $universial_apk
cp "$(ls -t ${apk_path}/app-universal-release*.apk | head -n1)" $universial_apk
pnpm tauri android build -t aarch64
cp ${apk_path}/app-universal-release.apk $arm64_apk
cp "$(ls -t ${apk_path}/app-universal-release*.apk | head -n1)" $arm64_apk

echo "Uploading $universial_apk to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} $universial_apk --clobber
Expand Down
53 changes: 20 additions & 33 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,28 @@ pnpm preview
Android:

```bash
# 初始化 Android 环境(运行一次)
# 初始化 Android 环境(运行一次),需要提前安装Android开发环境,Windows上需要打开发者模式
rm app/src-tauri/gen/android
pnpm tauri android init
pnpm tauri icon ../../data/icons/myreader-book.png
git checkout app/src-tauri/gen/android
# app/src-tauri/gen/android 整个目录被 .gitignore 排除,不会被 git 追踪,
# 所以每次 init 都会重新生成一份不带下面这行补丁的 build.gradle.kts。
# tauri-plugin-native-bridge 声明了 foss/googleplay 两个 store 维度的 flavor,
# 缺这一行 Gradle 会因为无法在两者间选择而构建失败,每次 init 后都要重新执行:
sed -i '/defaultConfig {/a\ missingDimensionStrategy("store", "foss", "googleplay")' app/src-tauri/gen/android/app/build.gradle.kts
pnpm tauri icon ../data/icons/myreader-book.png

pnpm tauri android dev
# 或在真机上开发
pnpm tauri android dev --host
pnpm tauri android dev --host <dev pc ip>
```

```bash
# 构建APK
cd app
# 打包全架构包(universal)
pnpm tauri android build
# 只打包aarch64的包
pnpm tauri android build -t aarch64
```

iOS:
Expand Down
8 changes: 7 additions & 1 deletion app/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ const nextConfig = {
assetPrefix: '',
reactStrictMode: true,
serverExternalPackages: ['isows'],
allowedDevOrigins: ['192.168.2.120'],
// Static entry is a stale LAN IP from a prior network; keep it as a
// harmless fallback and additionally allow whatever IP tauri-cli picked
// for `--host <ip>` this run (forwarded via TAURI_DEV_HOST, see layout.tsx).
allowedDevOrigins: [
'192.168.2.120',
...(process.env['TAURI_DEV_HOST'] ? [process.env['TAURI_DEV_HOST']] : []),
],
webpack: (config) => {
config.resolve.alias = {
...config.resolve.alias,
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@poxenstudio/myreader",
"version": "0.1.0",
"version": "0.2.0",
"private": true,
"type": "module",
"scripts": {
Expand Down
4 changes: 4 additions & 0 deletions app/release-notes.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"releases": {
"0.2.0": {
"date": "2026-07-14",
"notes": ["Android版本发布", "支持MyBooks开启私人图书馆模式的登录"]
},
"0.1.0": {
"date": "2026-06-28",
"notes": ["Initial release"]
Expand Down
4 changes: 3 additions & 1 deletion app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ tauri-plugin-webview-upgrade = { path = "./plugins/tauri-plugin-webview-upgrade"
tauri-plugin-websocket = "2"
tauri-plugin-sharekit = "0.3"
tauri-plugin-device-info = "1.0.1"
tauri-plugin-turso = { path = "./plugins/tauri-plugin-turso" }
tauri-plugin-webdriver = { version = "0.2", optional = true }

[target."cfg(target_os = \"macos\")".dependencies]
Expand All @@ -80,5 +79,8 @@ tauri-plugin-single-instance = "2"
tauri-plugin-updater = "2"
tauri-plugin-window-state = "2"

[target.'cfg(not(target_os = "android"))'.dependencies]
tauri-plugin-turso = { path = "./plugins/tauri-plugin-turso" }

[target.'cfg(target_os = "android")'.dependencies]
libc = "0.2"
1 change: 0 additions & 1 deletion app/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@
"deep-link:default",
"sharekit:default",
"device-info:default",
"turso:default",
"native-tts:default",
"native-bridge:default"
]
Expand Down
2 changes: 1 addition & 1 deletion app/src-tauri/capabilities/desktop.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"identifier": "desktop-capability",
"windows": ["main", "updater", "reader-*"],
"platforms": ["linux", "macOS", "windows"],
"permissions": ["updater:default", "cli:default"]
"permissions": ["updater:default", "cli:default", "turso:default"]
}
Binary file modified app/src-tauri/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/128x128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/64x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square107x107Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square142x142Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square150x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square284x284Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square30x30Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square310x310Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square44x44Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square71x71Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/Square89x89Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/StoreLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions app/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
</adaptive-icon>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<background android:drawable="@color/ic_launcher_background"/>
</adaptive-icon>
Binary file modified app/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Binary file modified app/src-tauri/icons/icon.icns
Binary file not shown.
Binary file modified app/src-tauri/icons/icon.ico
Binary file not shown.
Binary file modified app/src-tauri/icons/icon.png
Binary file modified app/src-tauri/icons/ios/AppIcon-20x20@1x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Binary file modified app/src-tauri/icons/ios/AppIcon-20x20@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-20x20@3x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-29x29@1x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Binary file modified app/src-tauri/icons/ios/AppIcon-29x29@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-29x29@3x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-40x40@1x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Binary file modified app/src-tauri/icons/ios/AppIcon-40x40@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-40x40@3x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-512@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-60x60@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-60x60@3x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-76x76@1x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-76x76@2x.png
Binary file modified app/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
9 changes: 6 additions & 3 deletions app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,12 @@ pub fn run() {
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_sharekit::init())
.plugin(tauri_plugin_device_info::init())
.plugin(tauri_plugin_turso::init())
.plugin(tauri_plugin_native_bridge::init())
.plugin(tauri_plugin_device_info::init());

#[cfg(not(target_os = "android"))]
let builder = builder.plugin(tauri_plugin_turso::init());

let builder = builder.plugin(tauri_plugin_native_bridge::init())
.plugin(tauri_plugin_native_tts::init())
.plugin(tauri_plugin_webview_upgrade::init());

Expand Down
2 changes: 1 addition & 1 deletion app/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"minSdkVersion": 26
},
"iOS": {
"developmentTeam": "J5W48D69VR",
"developmentTeam": "MHNRDP49V2",
"infoPlist": "./Info-ios.plist",
"minimumSystemVersion": "15.0"
},
Expand Down
Loading
Loading