Skip to content

Commit 52fb9e8

Browse files
authored
Merge pull request #199 from winnerspiros/copilot/fix-apk-installation-error
Fix APK signing, merge upstream ppy/osu, optimize Android performance & input
2 parents 0802f04 + 793a587 commit 52fb9e8

210 files changed

Lines changed: 6524 additions & 1870 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.config/dotnet-tools.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"rollForward": false
1111
},
1212
"codefilesanity": {
13-
"version": "0.0.37",
13+
"version": "0.0.41",
1414
"commands": [
1515
"CodeFileSanity"
1616
],
@@ -24,4 +24,4 @@
2424
"rollForward": false
2525
}
2626
}
27-
}
27+
}

.github/workflows/release.yml

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@ jobs:
4848
NDK_HOME="$ANDROID_HOME/ndk/29.0.14206865"
4949
CMAKE_BIN="$ANDROID_HOME/cmake/3.22.1/bin/cmake"
5050
51-
# Only build arm64 and arm32. x86 removed to reduce APK size —
52-
# modern emulators use x86_64 or ARM translation.
53-
for ABI in arm64-v8a armeabi-v7a; do
51+
# arm64 only — matches RuntimeIdentifiers in osu.Android.props.
52+
for ABI in arm64-v8a; do
5453
echo "::group::Building osu_native for $ABI"
5554
"$CMAKE_BIN" -B "build-native/$ABI" -S osu.Android/Native \
5655
-DCMAKE_TOOLCHAIN_FILE="$NDK_HOME/build/cmake/android.toolchain.cmake" \
@@ -148,6 +147,55 @@ jobs:
148147
echo "Found APK: $APK ($APK_SIZE_MB MB)"
149148
echo "apk_path=$APK" >> "$GITHUB_OUTPUT"
150149
150+
# .NET 10 Android SDK may skip debug-signing for Release publish builds.
151+
# Verify the APK is signed; if not, sign it with apksigner using the debug
152+
# keystore so the APK can be sideloaded without INSTALL_PARSE_FAILED_NO_CERTIFICATES.
153+
- name: Verify and sign APK if needed
154+
run: |
155+
APK="${{ steps.find_apk.outputs.apk_path }}"
156+
APKSIGNER="$ANDROID_HOME/build-tools/$(ls "$ANDROID_HOME/build-tools" | sort -V | tail -1)/apksigner"
157+
ZIPALIGN="$ANDROID_HOME/build-tools/$(ls "$ANDROID_HOME/build-tools" | sort -V | tail -1)/zipalign"
158+
159+
if "$APKSIGNER" verify "$APK" 2>/dev/null; then
160+
echo "APK is already signed ✓"
161+
else
162+
echo "::warning::APK is not signed. Signing with debug keystore..."
163+
164+
# Generate debug keystore if it doesn't exist
165+
DEBUG_KS="$HOME/.android/debug.keystore"
166+
if [ ! -f "$DEBUG_KS" ]; then
167+
mkdir -p "$HOME/.android"
168+
keytool -genkeypair -v \
169+
-keystore "$DEBUG_KS" \
170+
-storepass android \
171+
-keypass android \
172+
-alias androiddebugkey \
173+
-keyalg RSA -keysize 2048 -validity 10000 \
174+
-dname "CN=Android Debug,O=Android,C=US"
175+
fi
176+
177+
# Zipalign first (required before apksigner v2 signing)
178+
ALIGNED_APK="${APK%.apk}-aligned.apk"
179+
"$ZIPALIGN" -f -p 4 "$APK" "$ALIGNED_APK"
180+
mv "$ALIGNED_APK" "$APK"
181+
182+
# Sign with debug keystore (v1 + v2 + v3 schemes)
183+
"$APKSIGNER" sign \
184+
--ks "$DEBUG_KS" \
185+
--ks-pass pass:android \
186+
--key-pass pass:android \
187+
--ks-key-alias androiddebugkey \
188+
"$APK"
189+
190+
# Verify signature
191+
if "$APKSIGNER" verify --print-certs "$APK"; then
192+
echo "APK signed successfully ✓"
193+
else
194+
echo "::error::APK signing failed"
195+
exit 1
196+
fi
197+
fi
198+
151199
- name: Upload APK artifact
152200
uses: actions/upload-artifact@v7
153201
with:

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Thank you for showing interest in the development of osu!. We aim to provide a good collaborating environment for everyone involved, and as such have decided to list some of the most important things to keep in mind in the process. The guidelines below have been chosen based on past experience.
44

5+
## Foreword on AI usage
6+
7+
Our team believes in **human contributions**. Any contribution – be it an issue report or a pull request – which is created by, documented by, or aided by AI/LLM usage will typically be **closed and locked without further discussion**.
8+
59
## Table of contents
610

711
1. [Reporting bugs](#reporting-bugs)

README.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ You can see some examples of custom rulesets by visiting the [custom ruleset dir
5151

5252
Please make sure you have the following prerequisites:
5353

54-
- A desktop platform with the [.NET 8.0 SDK](https://dotnet.microsoft.com/download) installed.
54+
- A desktop platform with the [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) installed (this fork targets .NET 10; upstream ppy/osu uses .NET 8).
5555

5656
When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/), or [Visual Studio Code](https://code.visualstudio.com/) with the [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) and [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) plugin installed.
5757

@@ -96,6 +96,68 @@ When running locally to do any kind of performance testing, make sure to add `-c
9696

9797
If the build fails, try to restore NuGet packages with `dotnet restore`.
9898

99+
#### Building for Android
100+
101+
**Prerequisites:**
102+
- [.NET 10.0 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) (this fork targets .NET 10)
103+
- JDK 17 (`sudo apt install openjdk-17-jdk` or use [Microsoft's JDK](https://learn.microsoft.com/en-us/java/openjdk/download))
104+
- Android workload: `dotnet workload install android`
105+
106+
**Debug build** (auto-signed with debug keystore, suitable for local testing):
107+
108+
```shell
109+
dotnet build -c Debug osu.Android/osu.Android.csproj
110+
```
111+
112+
The APK will be at `osu.Android/bin/Debug/net10.0-android/sh.ppy.osulazer.apk`. Debug builds are always signed with the Android debug keystore and can be installed directly via `adb install`.
113+
114+
**Release build** (optimised with AOT, trimming, and compression):
115+
116+
```shell
117+
dotnet publish -c Release osu.Android/osu.Android.csproj -f net10.0-android
118+
```
119+
120+
The APK will be at `osu.Android/bin/Release/net10.0-android/publish/sh.ppy.osulazer.apk`.
121+
122+
**Signing the Release APK:**
123+
124+
Release APKs may not be automatically signed by the .NET SDK. If you get `INSTALL_PARSE_FAILED_NO_CERTIFICATES` when installing, sign the APK manually:
125+
126+
```shell
127+
# Find your build-tools (adjust version as needed)
128+
BUILD_TOOLS="$ANDROID_HOME/build-tools/$(ls $ANDROID_HOME/build-tools | sort -V | tail -1)"
129+
130+
# Zipalign (required before signing)
131+
"$BUILD_TOOLS/zipalign" -f -p 4 sh.ppy.osulazer.apk sh.ppy.osulazer-aligned.apk
132+
mv sh.ppy.osulazer-aligned.apk sh.ppy.osulazer.apk
133+
134+
# Sign with debug keystore (or your own release keystore)
135+
"$BUILD_TOOLS/apksigner" sign \
136+
--ks ~/.android/debug.keystore \
137+
--ks-pass pass:android \
138+
--key-pass pass:android \
139+
--ks-key-alias androiddebugkey \
140+
sh.ppy.osulazer.apk
141+
142+
# Verify
143+
"$BUILD_TOOLS/apksigner" verify sh.ppy.osulazer.apk
144+
```
145+
146+
If `~/.android/debug.keystore` does not exist, generate it:
147+
148+
```shell
149+
keytool -genkeypair -v -keystore ~/.android/debug.keystore \
150+
-storepass android -keypass android -alias androiddebugkey \
151+
-keyalg RSA -keysize 2048 -validity 10000 \
152+
-dname "CN=Android Debug,O=Android,C=US"
153+
```
154+
155+
**Install via ADB:**
156+
157+
```shell
158+
adb install sh.ppy.osulazer.apk
159+
```
160+
99161
### Testing with resource/framework modifications
100162

101163
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be quickly achieved using included commands:
@@ -138,6 +200,8 @@ If you wish to help with localisation efforts, head over to [crowdin](https://cr
138200

139201
We love to reward quality contributions. If you have made a large contribution, or are a regular contributor, you are welcome to [submit an expense via opencollective](https://opencollective.com/ppy/expenses/new). If you have any questions, feel free to [reach out to peppy](mailto:pe@ppy.sh) before doing so.
140202

203+
Our team believes in **human contributions**. Any contribution – be it an issue report or a pull request – which is created by, documented by, or aided by AI/LLM usage will typically be **closed and locked without further discussion**.
204+
141205
## Licence
142206

143207
*osu!*'s code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.

osu.Android.props

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
<Project>
22
<PropertyGroup>
33
<SupportedOSPlatformVersion>33.0</SupportedOSPlatformVersion>
4-
<!-- arm64-v8a covers 99%+ of modern Android devices.
5-
armeabi-v7a is kept for older 32-bit devices.
6-
x86 removed — only used by legacy emulators; modern x86_64 emulators
7-
run arm64 binaries via native translation (no dedicated x86 build needed). -->
8-
<RuntimeIdentifiers>android-arm;android-arm64</RuntimeIdentifiers>
4+
<!-- arm64-v8a only. Modern Android devices are 99%+ arm64; 32-bit arm32 (armeabi-v7a)
5+
adds ~200 MB of duplicate native libraries for negligible device coverage.
6+
x86 was already removed — modern x86_64 emulators run arm64 via translation. -->
7+
<RuntimeIdentifiers>android-arm64</RuntimeIdentifiers>
98
<AndroidPackageFormat>apk</AndroidPackageFormat>
109
<!-- CJK and Mideast encodings are needed for song metadata display.
1110
Rare covers supplementary Unicode blocks. West is the default Latin set. -->
@@ -68,12 +67,7 @@
6867
</ItemGroup>
6968

7069
<ItemGroup>
71-
<!-- IMPORTANT: ppy.osu.Framework.Android v2026.318.0 only ships net8.0-android34.0 assets.
72-
NuGet silently falls back to those assets when the app targets net10.0-android (API 36).
73-
This is safe because .NET guarantees backward compatibility for loading net8.0 assemblies
74-
in a net10.0 runtime, and Android API changes between 34→36 are additive.
75-
TODO: Remove this comment once ppy.osu.Framework.Android ships net10.0-android assets. -->
76-
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.318.0" />
70+
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.416.0" />
7771
</ItemGroup>
7872

7973
<PropertyGroup>
@@ -82,19 +76,18 @@
8276
<DisableFody>true</DisableFody>
8377
</PropertyGroup>
8478

85-
<!-- Fix for .NET 10 Android AOT misclassifying non-managed assets in runtime pack.
86-
This is critical for Android 16 (API 36) Release/AOT builds where the linker expects
87-
all non-managed assets to be marked as native before the optimization/signing phases.
88-
Scoped to Release only — running this during Debug builds can interfere with how the
89-
Android SDK classifies signing-related items, leading to APKs with null certificate
90-
arrays (INSTALL_PARSE_FAILED_NO_CERTIFICATES). -->
79+
<!-- Fix for .NET 10 Android AOT misclassifying native .so assets in runtime pack.
80+
Only .so files need the AssetType override — the previous broader filter
81+
(all non-DLL, non-PDB) incorrectly reclassified signing metadata and config
82+
files, which corrupted the APK signature (INSTALL_PARSE_FAILED_NO_CERTIFICATES).
83+
Scoped to Release only to avoid interfering with Debug builds. -->
9184
<Target Name="FixRuntimePackAssetTypes" AfterTargets="ResolveRuntimePackAssets;ComputeFilesToPublish;ComputeResolvedFilesToPublishList"
9285
Condition="'$(Configuration)' == 'Release'">
9386
<ItemGroup>
94-
<RuntimePackAsset Update="@(RuntimePackAsset)" Condition="'%(Extension)' != '.dll' AND '%(Extension)' != '.pdb'">
87+
<RuntimePackAsset Update="@(RuntimePackAsset)" Condition="'%(Extension)' == '.so'">
9588
<AssetType>native</AssetType>
9689
</RuntimePackAsset>
97-
<ResolvedFileToPublish Update="@(ResolvedFileToPublish)" Condition="'%(Extension)' != '.dll' AND '%(Extension)' != '.pdb'">
90+
<ResolvedFileToPublish Update="@(ResolvedFileToPublish)" Condition="'%(Extension)' == '.so'">
9891
<AssetType>native</AssetType>
9992
</ResolvedFileToPublish>
10093
</ItemGroup>

osu.Android/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version='1.0' encoding='utf-8'?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="sh.ppy.osulazer" android:installLocation="auto">
33
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="36" />
4-
<application android:extractNativeLibs="false" android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher" android:largeHeap="true">
4+
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher" android:largeHeap="true" android:hardwareAccelerated="true">
55
<provider android:name="androidx.core.content.FileProvider" android:authorities="sh.ppy.osulazer.fileprovider" android:grantUriPermissions="true" android:exported="false">
66
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
77
</provider>

0 commit comments

Comments
 (0)