fix(android): jedna ReactActivity (alias TV), pion z kodu, symbole natywne do Sentry; 0.4.3
Some checks failed
Backend tests / test (push) Waiting to run
Build Android APK / build (push) Has been cancelled

- TvMainActivity to activity-alias na MainActivity: dwie ReactActivity naraz
  walily asercja przy pauzie na Android TV
- blokada pionu w MainActivity.onCreate poza TV zamiast screenOrientation
  w manifescie (alias nie moze go nadpisac, TV ma ekran poziomy)
- Sentry Android Gradle Plugin: uploadNativeSymbols i mapping, tylko gdy build
  ma SENTRY_AUTH_TOKEN; autoInstallation i instrumentacja wylaczone
- versionCode 17, versionName 0.4.3
This commit is contained in:
goon-foss 2026-10-13 11:08:45 +02:00
parent 11400c01cb
commit df6b6c7f3f
6 changed files with 73 additions and 27 deletions

View file

@ -93,6 +93,33 @@ def jscFlavor = 'org.webkit:android-jsc:+'
apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle") apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle")
// Sentry Android Gradle Plugin: wysylka symboli natywnych (.so z build intermediates) i mappingu
// ProGuard. Bez tego natywne crashe SIGABRT (abort w JNI) maja same <unknown> w stosie.
// Wysylka tylko gdy build dostal SENTRY_AUTH_TOKEN (Infisical goon-app przez iclaude) i nie ma
// SENTRY_DISABLE_AUTO_UPLOAD=true; inaczej plugin jest bierny i build dziala offline.
// autoInstallation wylaczone: sentry-android przychodzi z @sentry/react-native, drugi egzemplarz
// w innej wersji psulby runtime. Instrumentacja bytecode tez wylaczona (nie potrzebujemy spanow
// OkHttp/Room, a zmienia kod bibliotek).
apply plugin: "io.sentry.android.gradle"
def sentryUploadEnabled = System.getenv("SENTRY_AUTH_TOKEN") &&
System.getenv("SENTRY_DISABLE_AUTO_UPLOAD") != "true"
sentry {
org = System.getenv("SENTRY_ORG")
projectName = System.getenv("SENTRY_PROJECT")
authToken = System.getenv("SENTRY_AUTH_TOKEN")
uploadNativeSymbols = sentryUploadEnabled
includeNativeSources = true
autoUploadProguardMapping = sentryUploadEnabled
includeProguardMapping = true
includeSourceContext = false
ignoredBuildTypes = ["debug"]
autoInstallation { enabled = false }
tracingInstrumentation { enabled = false }
telemetry = false
}
android { android {
ndkVersion rootProject.ext.ndkVersion ndkVersion rootProject.ext.ndkVersion
@ -104,8 +131,8 @@ android {
applicationId 'com.goon.mobile' applicationId 'com.goon.mobile'
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 16 versionCode 17
versionName "0.4.2" versionName "0.4.3"
} }
signingConfigs { signingConfigs {
debug { debug {

View file

@ -49,7 +49,9 @@
gdy Chromium probowal podpiac skaner kodow (GOON-3B, 3 crashe od lipca). --> gdy Chromium probowal podpiac skaner kodow (GOON-3B, 3 crashe od lipca). -->
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<activity android:name="com.reactnative.googlecast.RNGCExpandedControllerActivity"/> <activity android:name="com.reactnative.googlecast.RNGCExpandedControllerActivity"/>
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait" android:resizeableActivity="true"> <!-- Bez android:screenOrientation: pion wymusza MainActivity.onCreate (tylko poza TV),
bo wpis w manifescie dotyczylby tez aliasu telewizyjnego ponizej. -->
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:resizeableActivity="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
@ -63,12 +65,14 @@
</activity> </activity>
<!-- Android TV. Bez wpisu LEANBACK_LAUNCHER apka nie pojawia sie na ekranie glownym <!-- Android TV. Bez wpisu LEANBACK_LAUNCHER apka nie pojawia sie na ekranie glownym
telewizora, mimo ze instaluje sie bez bledu. Banner (320x180) jest w <application>. telewizora, mimo ze instaluje sie bez bledu. Banner (320x180) jest w <application>.
Osobna aktywnosc, bo tu NIE MA blokady pionu, patrz TvMainActivity. --> Alias tej samej aktywnosci (nie osobna klasa): dwie ReactActivity naraz walily
<activity android:name=".TvMainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:resizeableActivity="true"> asercja przy pauzie (crash na TV), a nazwa .TvMainActivity zostaje, zeby skroty
na ekranach telewizorow dalej dzialaly. -->
<activity-alias android:name=".TvMainActivity" android:targetActivity=".MainActivity" android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/> <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity-alias>
</application> </application>
</manifest> </manifest>

View file

@ -1,5 +1,10 @@
package com.goon.mobile package com.goon.mobile
import android.app.UiModeManager
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -13,9 +18,28 @@ import com.reactnative.googlecast.api.RNGCCastContext
import expo.modules.ReactActivityDelegateWrapper import expo.modules.ReactActivityDelegateWrapper
// open, bo dziedziczy z niej TvMainActivity (to samo, tylko bez blokady pionu). /**
* Jedyna aktywnosc Reacta w aplikacji. Wejscie dla Android TV (`.TvMainActivity`,
* LEANBACK_LAUNCHER) to w manifescie activity-alias na te klase, a nie osobna klasa.
*
* Dlaczego (najczestszy crash na telewizorach do 2026-10): osobna `TvMainActivity :
* MainActivity()` byla DRUGA ReactActivity na tym samym ReactInstanceManager. Na telewizorze
* obie potrafily zyc naraz (launcher TV startuje Tv, a intent MAIN/VIEW, Cast albo Recents
* wchodzi w MainActivity) i pauza tej, ktora nie byla "current", walila asercja
* `Unable to pause activity TvMainActivity`. Jedna klasa + `singleTask` = jedna instancja.
*
* Blokada pionu: nie w manifescie (alias nie moze jej nadpisac, a telewizor ma ekran na stale
* poziomy i pionowa aplikacja wychodzi waskim paskiem), tylko tutaj, przed `super.onCreate`,
* i TYLKO poza telewizorem. Na TV nie wolno wolac `setRequestedOrientation` (relaunch tuz po
* starcie i bialy ekran, sprawdzone 2026-09-17). Telefon startuje niemal zawsze w pionie,
* wiec zadanie pionu nie zmienia konfiguracji; gdyby zmienilo, `configChanges` w manifescie
* obsluguje orientation|screenSize bez odtwarzania aktywnosci.
*/
open class MainActivity : ReactActivity() { open class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
if (!isTelevision()) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
// Set the theme to AppTheme BEFORE onCreate to support // Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar. // coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen. // This is required for expo-splash-screen.
@ -33,6 +57,12 @@ open class MainActivity : ReactActivity() {
} }
} }
private fun isTelevision(): Boolean {
val uiMode = getSystemService(Context.UI_MODE_SERVICE) as? UiModeManager
if (uiMode?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) return true
return packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
}
/** /**
* Returns the name of the main component registered from JavaScript. This is used to schedule * Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component. * rendering of the component.

View file

@ -1,19 +0,0 @@
package com.goon.mobile
/**
* Wejscie dla Android TV. Ta sama aktywnosc co na telefonie, rozni sie WYLACZNIE wpisem
* w manifescie: telefon ma blokade pionu, telewizor jej nie ma, bo ekran telewizora jest
* na stale poziomy i pionowa aplikacja wychodzi tam waskim paskiem na srodku.
*
* Dlaczego osobna klasa, a nie jedna aktywnosc:
* - `setRequestedOrientation` w `onCreate` to zmiana konfiguracji, wiec system
* relaunchuje aktywnosc tuz po starcie i na TV zostawal bialy ekran (widok Reacta nie
* wracal; emulator android-34 android-tv, 2026-09-17),
* - orientacja z zasobu (`values-television`) nie przechodzi, bo manifest czyta zasoby
* bez kontekstu konfiguracji (lint ManifestResource),
* - `activity-alias` nie pozwala nadpisac `screenOrientation`.
*
* Telewizorowy launcher pyta o `LEANBACK_LAUNCHER`, wiec na telefonie ta klasa jest
* niewidoczna, a na TV widoczna jest tylko ona.
*/
class TvMainActivity : MainActivity()

View file

@ -23,6 +23,10 @@ buildscript {
classpath('com.android.tools.build:gradle') classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin') classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
// Symbole natywne (.so) i mapping ProGuard do Sentry. sentry.gradle z @sentry/react-native
// wysyla tylko bundle JS i source mapy; natywne crashe SIGABRT byly przez to
// nieczytelne. Wersja 4.14.x dziala z AGP 8.x i sentry-android 7.x z RN SDK 6.10.
classpath('io.sentry:sentry-android-gradle-plugin:4.14.1')
} }
} }

View file

@ -2,7 +2,7 @@
"expo": { "expo": {
"name": "goon", "name": "goon",
"slug": "goon", "slug": "goon",
"version": "0.4.2", "version": "0.4.3",
"orientation": "portrait", "orientation": "portrait",
"userInterfaceStyle": "automatic", "userInterfaceStyle": "automatic",
"newArchEnabled": false, "newArchEnabled": false,