docs: add README + setup screenshot; add .gitignore, untrack build/gradle artifacts

This commit is contained in:
2026-06-19 09:08:35 +00:00
parent 62d7c929fe
commit 70ac1cd90e
2847 changed files with 64 additions and 325978 deletions
+13
View File
@@ -0,0 +1,13 @@
*.iml
.gradle/
.kotlin/
local.properties
.idea/
.DS_Store
/build/
app/build/
captures/
.externalNativeBuild/
.cxx/
*.keystore
*.jks
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View File
Binary file not shown.
@@ -1,2 +0,0 @@
#Thu Jun 04 12:16:33 UTC 2026
gradle.version=8.6
Binary file not shown.
Binary file not shown.
View File
+51
View File
@@ -0,0 +1,51 @@
# Homelab MFA
Biometric push-approval for your homelab logins. When you sign in through Authentik, your phone
buzzes — approve with a fingerprint, or deny with one tap. A self-hosted alternative to Duo /
Authy push, with **no third-party cloud** in the loop.
## How it works
1. You log in via **Authentik**. A flow step fires an **ntfy** notification to your phone with two
action buttons: **Approve** and **Deny**.
2. The buttons are `homemfa://approve?token=…` / `homemfa://deny?token=…` deep links that open this app.
3. **Approve** triggers a biometric prompt (fingerprint / face / device PIN). On success the app
POSTs `approve:<token>` to `ntfy.khodak.me/mfa-approve`; your Authentik flow is listening on that
topic and completes the login.
4. **Deny** POSTs `deny:<token>` to `mfa-deny` and blocks the login — no biometric needed to reject.
The activity is `showWhenLocked` + `turnScreenOn`, so an approval works straight from the lock screen.
## Features
- **Biometric gate** — `BIOMETRIC_STRONG` or device credential required to approve (deny is instant)
- **Lock-screen ready** — wakes the screen and shows over the keyguard
- **Self-hosted** — talks only to your own ntfy instance; no Firebase, no vendor cloud
- **Zero stored secrets** — stateless; each request carries a one-time token
- **Setup self-check** — a "Test Biometric" button confirms enrollment before you rely on it
## Screenshots
<p align="center">
<img src="docs/screenshots/setup.png" width="240" alt="Setup screen">
</p>
## Install
1. Download `homelab-mfa.apk` from the [latest release](../../releases/latest)
2. On your Android phone: **Settings → Apps → Install unknown apps** → allow your browser/file manager
3. Open the APK and tap Install
4. Open **Homelab MFA** and tap **Test Biometric** to confirm your fingerprint is enrolled
## Server side
You need:
- An **ntfy** instance reachable at `ntfy.khodak.me` (or change the host in `MainActivity.kt`)
- An **Authentik** flow that, on login, publishes a notification with the two `homemfa://` action
buttons, then waits on the `mfa-approve` / `mfa-deny` topics for the decision
## Requirements
- Android 9.0+ (API 28)
- A fingerprint, face, or device PIN enrolled
@@ -1,90 +0,0 @@
// Generated by view binder compiler. Do not edit!
package me.khodak.mfa.databinding;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewbinding.ViewBinding;
import androidx.viewbinding.ViewBindings;
import java.lang.NullPointerException;
import java.lang.Override;
import java.lang.String;
import me.khodak.mfa.R;
public final class ActivityMainBinding implements ViewBinding {
@NonNull
private final LinearLayout rootView;
@NonNull
public final ImageView icon;
@NonNull
public final TextView statusText;
@NonNull
public final TextView subText;
private ActivityMainBinding(@NonNull LinearLayout rootView, @NonNull ImageView icon,
@NonNull TextView statusText, @NonNull TextView subText) {
this.rootView = rootView;
this.icon = icon;
this.statusText = statusText;
this.subText = subText;
}
@Override
@NonNull
public LinearLayout getRoot() {
return rootView;
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.activity_main, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}
@NonNull
public static ActivityMainBinding bind(@NonNull View rootView) {
// The body of this method is generated in a way you would not otherwise write.
// This is done to optimize the compiled bytecode for size and performance.
int id;
missingId: {
id = R.id.icon;
ImageView icon = ViewBindings.findChildViewById(rootView, id);
if (icon == null) {
break missingId;
}
id = R.id.statusText;
TextView statusText = ViewBindings.findChildViewById(rootView, id);
if (statusText == null) {
break missingId;
}
id = R.id.subText;
TextView subText = ViewBindings.findChildViewById(rootView, id);
if (subText == null) {
break missingId;
}
return new ActivityMainBinding((LinearLayout) rootView, icon, statusText, subText);
}
String missingId = rootView.getResources().getResourceName(id);
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}
@@ -1,102 +0,0 @@
// Generated by view binder compiler. Do not edit!
package me.khodak.mfa.databinding;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewbinding.ViewBinding;
import androidx.viewbinding.ViewBindings;
import java.lang.NullPointerException;
import java.lang.Override;
import java.lang.String;
import me.khodak.mfa.R;
public final class ActivityMainBinding implements ViewBinding {
@NonNull
private final LinearLayout rootView;
@NonNull
public final Button actionButton;
@NonNull
public final ImageView icon;
@NonNull
public final TextView statusText;
@NonNull
public final TextView subText;
private ActivityMainBinding(@NonNull LinearLayout rootView, @NonNull Button actionButton,
@NonNull ImageView icon, @NonNull TextView statusText, @NonNull TextView subText) {
this.rootView = rootView;
this.actionButton = actionButton;
this.icon = icon;
this.statusText = statusText;
this.subText = subText;
}
@Override
@NonNull
public LinearLayout getRoot() {
return rootView;
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
@NonNull
public static ActivityMainBinding inflate(@NonNull LayoutInflater inflater,
@Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.activity_main, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}
@NonNull
public static ActivityMainBinding bind(@NonNull View rootView) {
// The body of this method is generated in a way you would not otherwise write.
// This is done to optimize the compiled bytecode for size and performance.
int id;
missingId: {
id = R.id.actionButton;
Button actionButton = ViewBindings.findChildViewById(rootView, id);
if (actionButton == null) {
break missingId;
}
id = R.id.icon;
ImageView icon = ViewBindings.findChildViewById(rootView, id);
if (icon == null) {
break missingId;
}
id = R.id.statusText;
TextView statusText = ViewBindings.findChildViewById(rootView, id);
if (statusText == null) {
break missingId;
}
id = R.id.subText;
TextView subText = ViewBindings.findChildViewById(rootView, id);
if (subText == null) {
break missingId;
}
return new ActivityMainBinding((LinearLayout) rootView, actionButton, icon, statusText,
subText);
}
String missingId = rootView.getResources().getResourceName(id);
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}
@@ -1,92 +0,0 @@
-keep class androidx.core.app.CoreComponentFactory { <init>(); }
-keep class androidx.profileinstaller.ProfileInstallReceiver { <init>(); }
-keep class androidx.startup.InitializationProvider { <init>(); }
-keep class me.khodak.mfa.MainActivity { <init>(); }
-keep class android.widget.Space { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.app.AlertController$RecycleListView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.view.menu.ActionMenuItemView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.view.menu.ExpandedMenuView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.view.menu.ListMenuItemView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ActionBarContainer { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ActionBarContextView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ActionBarOverlayLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ActionMenuView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ActivityChooserView$InnerLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.AlertDialogLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ButtonBarLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ContentFrameLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.DialogTitle { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.FitWindowsFrameLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.FitWindowsLinearLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.SearchView$SearchAutoComplete { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.Toolbar { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.appcompat.widget.ViewStubCompat { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.constraintlayout.helper.widget.Flow { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.constraintlayout.widget.ConstraintLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.coordinatorlayout.widget.CoordinatorLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.core.widget.NestedScrollView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.fragment.app.FragmentContainerView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class androidx.recyclerview.widget.RecyclerView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.appbar.MaterialToolbar { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.button.MaterialButton { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.button.MaterialButtonToggleGroup { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.chip.Chip { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.datepicker.MaterialCalendarGridView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.BaselineLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.CheckableImageButton { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.ClippableRoundedCornerLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.NavigationMenuItemView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.NavigationMenuView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.internal.TouchObserverFrameLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.snackbar.Snackbar$SnackbarLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.snackbar.SnackbarContentLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.textfield.TextInputEditText { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.textfield.TextInputLayout { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.timepicker.ChipTextInputComboView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.timepicker.ClockFaceView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.timepicker.ClockHandView { <init>(android.content.Context, android.util.AttributeSet); }
-keep class com.google.android.material.timepicker.TimePickerView { <init>(android.content.Context, android.util.AttributeSet); }
@@ -1,2 +0,0 @@
#- File Locator -
listingFile=../../../outputs/apk/debug/output-metadata.json
@@ -1,2 +0,0 @@
#- File Locator -
listingFile=../../../outputs/apk/release/output-metadata.json
@@ -1,2 +0,0 @@
appMetadataVersion=1.1
androidGradlePluginVersion=8.2.2
@@ -1,2 +0,0 @@
appMetadataVersion=1.1
androidGradlePluginVersion=8.2.2
@@ -1,94 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.khodak.mfa"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="28"
android:targetSdkVersion="34" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<!-- suppress DeprecatedClassUsageInspection -->
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<permission
android:name="me.khodak.mfa.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
android:protectionLevel="signature" />
<uses-permission android:name="me.khodak.mfa.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" />
<application
android:allowBackup="false"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
android:extractNativeLibs="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@drawable/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.HomelabMFA"
android:usesCleartextTraffic="false" >
<activity
android:name="me.khodak.mfa.MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:showWhenLocked="true"
android:turnScreenOn="true" >
<!-- App drawer launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Handle homemfa://approve?token=... and homemfa://deny?token=... -->
<intent-filter android:autoVerify="false" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="homemfa" />
</intent-filter>
</activity>
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="me.khodak.mfa.androidx-startup"
android:exported="false" >
<meta-data
android:name="androidx.emoji2.text.EmojiCompatInitializer"
android:value="androidx.startup" />
<meta-data
android:name="androidx.lifecycle.ProcessLifecycleInitializer"
android:value="androidx.startup" />
<meta-data
android:name="androidx.profileinstaller.ProfileInstallerInitializer"
android:value="androidx.startup" />
</provider>
<receiver
android:name="androidx.profileinstaller.ProfileInstallReceiver"
android:directBootAware="false"
android:enabled="true"
android:exported="true"
android:permission="android.permission.DUMP" >
<intent-filter>
<action android:name="androidx.profileinstaller.action.INSTALL_PROFILE" />
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SKIP_FILE" />
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SAVE_PROFILE" />
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION" />
</intent-filter>
</receiver>
</application>
</manifest>
@@ -1,10 +0,0 @@
{
"version": 3,
"artifactType": {
"type": "COMPATIBLE_SCREEN_MANIFEST",
"kind": "Directory"
},
"applicationId": "me.khodak.mfa.debug",
"variantName": "debug",
"elements": []
}
@@ -1,10 +0,0 @@
{
"version": 3,
"artifactType": {
"type": "COMPATIBLE_SCREEN_MANIFEST",
"kind": "Directory"
},
"applicationId": "me.khodak.mfa",
"variantName": "release",
"elements": []
}
@@ -1 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><Layout layout="activity_main" modulePackage="me.khodak.mfa" filePath="app/src/main/res/layout/activity_main.xml" directory="layout" isMerge="false" isBindingData="false" rootNodeType="android.widget.LinearLayout"><Targets><Target tag="layout/activity_main_0" view="LinearLayout"><Expressions/><location startLine="1" startOffset="0" endLine="36" endOffset="14"/></Target><Target id="@+id/icon" view="ImageView"><Expressions/><location startLine="9" startOffset="4" endLine="14" endOffset="50"/></Target><Target id="@+id/statusText" view="TextView"><Expressions/><location startLine="16" startOffset="4" endLine="24" endOffset="49"/></Target><Target id="@+id/subText" view="TextView"><Expressions/><location startLine="26" startOffset="4" endLine="34" endOffset="34"/></Target></Targets></Layout>
@@ -1 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><Layout layout="activity_main" modulePackage="me.khodak.mfa" filePath="app/src/main/res/layout/activity_main.xml" directory="layout" isMerge="false" isBindingData="false" rootNodeType="android.widget.LinearLayout"><Targets><Target tag="layout/activity_main_0" view="LinearLayout"><Expressions/><location startLine="1" startOffset="0" endLine="49" endOffset="14"/></Target><Target id="@+id/icon" view="ImageView"><Expressions/><location startLine="9" startOffset="4" endLine="14" endOffset="50"/></Target><Target id="@+id/statusText" view="TextView"><Expressions/><location startLine="16" startOffset="4" endLine="24" endOffset="49"/></Target><Target id="@+id/subText" view="TextView"><Expressions/><location startLine="26" startOffset="4" endLine="36" endOffset="35"/></Target><Target id="@+id/actionButton" view="Button"><Expressions/><location startLine="38" startOffset="4" endLine="47" endOffset="42"/></Target></Targets></Layout>
@@ -1 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><Layout layout="activity_main" modulePackage="me.khodak.mfa" filePath="app/src/main/res/layout/activity_main.xml" directory="layout" isMerge="false" isBindingData="false" rootNodeType="android.widget.LinearLayout"><Targets><Target tag="layout/activity_main_0" view="LinearLayout"><Expressions/><location startLine="1" startOffset="0" endLine="36" endOffset="14"/></Target><Target id="@+id/icon" view="ImageView"><Expressions/><location startLine="9" startOffset="4" endLine="14" endOffset="50"/></Target><Target id="@+id/statusText" view="TextView"><Expressions/><location startLine="16" startOffset="4" endLine="24" endOffset="49"/></Target><Target id="@+id/subText" view="TextView"><Expressions/><location startLine="26" startOffset="4" endLine="34" endOffset="34"/></Target></Targets></Layout>
@@ -1 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?><Layout layout="activity_main" modulePackage="me.khodak.mfa" filePath="app/src/main/res/layout/activity_main.xml" directory="layout" isMerge="false" isBindingData="false" rootNodeType="android.widget.LinearLayout"><Targets><Target tag="layout/activity_main_0" view="LinearLayout"><Expressions/><location startLine="1" startOffset="0" endLine="49" endOffset="14"/></Target><Target id="@+id/icon" view="ImageView"><Expressions/><location startLine="9" startOffset="4" endLine="14" endOffset="50"/></Target><Target id="@+id/statusText" view="TextView"><Expressions/><location startLine="16" startOffset="4" endLine="24" endOffset="49"/></Target><Target id="@+id/subText" view="TextView"><Expressions/><location startLine="26" startOffset="4" endLine="36" endOffset="35"/></Target><Target id="@+id/actionButton" view="Button"><Expressions/><location startLine="38" startOffset="4" endLine="47" endOffset="42"/></Target></Targets></Layout>
@@ -1,117 +0,0 @@
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
# will be ignored by new version of the Android plugin for Gradle.
# Optimizations: If you don't want to optimize, use the proguard-android.txt configuration file
# instead of this one, which turns off the optimization flags.
# Adding optimization introduces certain risks, since for example not all optimizations performed by
# ProGuard works on all versions of Dalvik. The following flags turn off various optimizations
# known to have issues, but the list may not be complete or up to date. (The "arithmetic"
# optimization can be used if you are only targeting Android 2.0 or later.) Make sure you test
# thoroughly if you go this route.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# Preserve some attributes that may be required for reflection.
-keepattributes AnnotationDefault,
EnclosingMethod,
InnerClasses,
RuntimeVisibleAnnotations,
RuntimeVisibleParameterAnnotations,
RuntimeVisibleTypeAnnotations,
Signature
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
-keep public class com.google.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
-dontnote com.google.vending.licensing.ILicensingService
-dontnote com.google.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Keep setters in Views so that animations can still work.
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick.
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Preserve annotated Javascript interface methods.
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# The support libraries contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontnote android.support.**
-dontnote androidx.**
-dontwarn android.support.**
-dontwarn androidx.**
# This class is deprecated, but remains for backward compatibility.
-dontwarn android.util.FloatMath
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep class androidx.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keep @androidx.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <init>(...);
}
# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
-dontnote org.apache.http.**
-dontnote android.net.http.**
# These classes are duplicated between android.jar and core-lambda-stubs.jar.
-dontnote java.lang.invoke.**
@@ -1,116 +0,0 @@
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
# will be ignored by new version of the Android plugin for Gradle.
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize steps (and performs some
# of these optimizations on its own).
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
-dontoptimize
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# Preserve some attributes that may be required for reflection.
-keepattributes AnnotationDefault,
EnclosingMethod,
InnerClasses,
RuntimeVisibleAnnotations,
RuntimeVisibleParameterAnnotations,
RuntimeVisibleTypeAnnotations,
Signature
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
-keep public class com.google.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
-dontnote com.google.vending.licensing.ILicensingService
-dontnote com.google.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Keep setters in Views so that animations can still work.
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick.
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Preserve annotated Javascript interface methods.
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# The support libraries contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontnote android.support.**
-dontnote androidx.**
-dontwarn android.support.**
-dontwarn androidx.**
# This class is deprecated, but remains for backward compatibility.
-dontwarn android.util.FloatMath
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep class androidx.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keep @androidx.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <init>(...);
}
# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
-dontnote org.apache.http.**
-dontnote android.net.http.**
# These classes are duplicated between android.jar and core-lambda-stubs.jar.
-dontnote java.lang.invoke.**
@@ -1,117 +0,0 @@
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
# Starting with version 2.2 of the Android plugin for Gradle, this file is distributed together with
# the plugin and unpacked at build-time. The files in $ANDROID_HOME are no longer maintained and
# will be ignored by new version of the Android plugin for Gradle.
# Optimizations can be turned on and off in the 'postProcessing' DSL block.
# The configuration below is applied if optimizations are enabled.
# Adding optimization introduces certain risks, since for example not all optimizations performed by
# ProGuard works on all versions of Dalvik. The following flags turn off various optimizations
# known to have issues, but the list may not be complete or up to date. (The "arithmetic"
# optimization can be used if you are only targeting Android 2.0 or later.) Make sure you test
# thoroughly if you go this route.
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 5
-allowaccessmodification
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# Preserve some attributes that may be required for reflection.
-keepattributes AnnotationDefault,
EnclosingMethod,
InnerClasses,
RuntimeVisibleAnnotations,
RuntimeVisibleParameterAnnotations,
RuntimeVisibleTypeAnnotations,
Signature
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
-keep public class com.google.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
-dontnote com.google.vending.licensing.ILicensingService
-dontnote com.google.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Keep setters in Views so that animations can still work.
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick.
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Preserve annotated Javascript interface methods.
-keepclassmembers class * {
@android.webkit.JavascriptInterface <methods>;
}
# The support libraries contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontnote android.support.**
-dontnote androidx.**
-dontwarn android.support.**
-dontwarn androidx.**
# This class is deprecated, but remains for backward compatibility.
-dontwarn android.util.FloatMath
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep class androidx.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keep @androidx.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
@android.support.annotation.Keep <init>(...);
}
-keepclasseswithmembers class * {
@androidx.annotation.Keep <init>(...);
}
# These classes are duplicated between android.jar and org.apache.http.legacy.jar.
-dontnote org.apache.http.**
-dontnote android.net.http.**
# These classes are duplicated between android.jar and core-lambda-stubs.jar.
-dontnote java.lang.invoke.**
@@ -1 +0,0 @@
8

Some files were not shown because too many files have changed in this diff Show More