Add release signing and German reel handling

This commit is contained in:
2026-07-08 00:38:10 +02:00
parent f52121883f
commit 7e9a6d195d
4 changed files with 69 additions and 11 deletions
+3
View File
@@ -5,7 +5,10 @@
app/build/
build/
local.properties
keystore.properties
*.hprof
*.apk
*.aab
*.iml
*.jks
*.keystore
+25
View File
@@ -1,8 +1,19 @@
import java.util.Properties
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.plugin.compose")
}
val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystoreProperties = Properties().apply {
if (keystorePropertiesFile.exists()) {
keystorePropertiesFile.inputStream().use(::load)
}
}
val hasReleaseSigning = listOf("storeFile", "storePassword", "keyAlias", "keyPassword")
.all { keystoreProperties.getProperty(it).isNullOrBlank().not() }
android {
namespace = "com.example.instanoreels"
compileSdk = 36
@@ -17,9 +28,23 @@ android {
buildConfigField("String", "INSTAGRAM_PACKAGE", "\"com.instagram.android\"")
}
signingConfigs {
if (hasReleaseSigning) {
create("release") {
storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("storePassword")
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
}
}
}
buildTypes {
release {
isMinifyEnabled = false
if (hasReleaseSigning) {
signingConfig = signingConfigs.getByName("release")
}
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@@ -10,6 +10,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import java.text.Normalizer
class InstagramBlockerAccessibilityService : AccessibilityService() {
private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
@@ -192,16 +193,25 @@ class InstagramBlockerAccessibilityService : AccessibilityService() {
}
private fun shouldBackOutOfDmViewer(area: InstagramArea, snapshot: InstagramScreenSnapshot): Boolean {
val text = snapshot.searchableText
val looksLikeDmReelViewer = text.contains("reply to") ||
text.contains("reply to yourself") ||
text.contains("send to") ||
text.contains("see more") ||
text.contains("antworten") ||
text.contains("senden an")
val text = snapshot.searchableText.foldForMatching()
val looksLikeDmReelViewer = listOf(
"reply to",
"reply to yourself",
"send to",
"see more",
"antworten",
"senden an",
"an chat senden",
"an chats senden",
"teilen mit",
"weiterleiten",
).any { text.contains(it.foldForMatching()) }
// Any blocked Reel surface is safer to leave with Back. Instagram uses the
// middle-bottom area for different controls inside Reel viewers, so a
// coordinate tap there can hit "Send to" instead of the DM tab.
return area == InstagramArea.DM_THREAD ||
area == InstagramArea.REELS && inReelViewerFromDm ||
area == InstagramArea.REELS ||
looksLikeDmReelViewer
}
@@ -217,10 +227,15 @@ class InstagramBlockerAccessibilityService : AccessibilityService() {
get() = applicationContext.packageName
}
private fun String.foldForMatching(): String {
return Normalizer.normalize(lowercase(), Normalizer.Form.NFD)
.replace(Regex("\\p{Mn}+"), "")
.replace("ß", "ss")
}
private fun InstagramArea.isRedirectableBlockedArea(): Boolean {
return this in setOf(
InstagramArea.HOME_FEED,
InstagramArea.REELS,
InstagramArea.EXPLORE,
InstagramArea.SEARCH,
)
@@ -3,6 +3,7 @@ package com.example.instanoreels.accessibility
import com.example.instanoreels.data.BlockerSettings
import com.example.instanoreels.model.BlockDecision
import com.example.instanoreels.model.InstagramArea
import java.text.Normalizer
class InstagramScreenClassifier {
fun classify(snapshot: InstagramScreenSnapshot): InstagramArea {
@@ -111,10 +112,14 @@ class InstagramScreenClassifier {
"suggested for you",
"for you",
"vorgeschlagen",
"vorschläge",
"vorschlaege",
"vorschlage",
"weitere reels",
"für dich",
"fur dich",
)
val reelRecommendationKeywords = suggestedKeywords + listOf("more reels", "mehr reels")
val reelRecommendationKeywords = suggestedKeywords + listOf("more reels", "mehr reels", "weitere reels")
val homeKeywords = listOf("home", "startseite", "feed")
val dmInboxKeywords = listOf("messages", "direct", "inbox", "chats", "nachrichten", "postfach")
val dmInboxPreviewKeywords = listOf(
@@ -142,7 +147,17 @@ class InstagramScreenClassifier {
}
private fun String.containsAny(keywords: List<String>): Boolean {
return keywords.any { contains(it.lowercase()) }
val foldedText = foldForMatching()
return keywords.any { keyword ->
val foldedKeyword = keyword.foldForMatching()
contains(keyword.lowercase()) || foldedText.contains(foldedKeyword)
}
}
private fun String.foldForMatching(): String {
return Normalizer.normalize(lowercase(), Normalizer.Form.NFD)
.replace(Regex("\\p{Mn}+"), "")
.replace("ß", "ss")
}
private fun String.looksLikeAuthScreen(): Boolean {