diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..cd446bc --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,81 @@ +name: Generated APK AAB (Upload - Create Artifact To Github Action) + +env: + # The name of the main module repository + main_project_module: app + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + # Set Current Date As Env Variable + - name: Set current date as env variable + run: echo "date_today=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + + # Set Repository Name As Env Variable + - name: Set repository name as env variable + run: echo "repository_name=$(echo '${{ github.repository }}' | awk -F '/' '{print $2}')" >> $GITHUB_ENV + + - name: Set Up JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' # See 'Supported distributions' for available options + java-version: '17' + cache: 'gradle' + + - name: Change wrapper permissions + run: chmod +x ./gradlew + + # Run Tests Build + - name: Run gradle tests + run: ./gradlew test + + # Run Build Project + - name: Build gradle project + run: ./gradlew build + + # Create APK Debug + - name: Build apk debug project (APK) - ${{ env.main_project_module }} module + run: ./gradlew assembleDebug + + # Create APK Release + - name: Build apk release project (APK) - ${{ env.main_project_module }} module + run: ./gradlew assemble + + # Create Bundle AAB Release + # Noted for main module build [main_project_module]:bundleRelease + - name: Build app bundle release (AAB) - ${{ env.main_project_module }} module + run: ./gradlew ${{ env.main_project_module }}:bundleRelease + + # Upload Artifact Build + # Noted For Output [main_project_module]/build/outputs/apk/debug/ + - name: Upload APK Debug - ${{ env.repository_name }} + uses: actions/upload-artifact@v3 + with: + name: ${{ env.date_today }} - ${{ env.repository_name }} - APK(s) debug generated + path: ${{ env.main_project_module }}/build/outputs/apk/debug/ + + # Noted For Output [main_project_module]/build/outputs/apk/release/ + - name: Upload APK Release - ${{ env.repository_name }} + uses: actions/upload-artifact@v3 + with: + name: ${{ env.date_today }} - ${{ env.repository_name }} - APK(s) release generated + path: ${{ env.main_project_module }}/build/outputs/apk/release/ + + # Noted For Output [main_project_module]/build/outputs/bundle/release/ + - name: Upload AAB (App Bundle) Release - ${{ env.repository_name }} + uses: actions/upload-artifact@v3 + with: + name: ${{ env.date_today }} - ${{ env.repository_name }} - App bundle(s) AAB release generated + path: ${{ env.main_project_module }}/build/outputs/bundle/release/ diff --git a/README.md b/README.md index bc167bf..60a3db6 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,48 @@ # Killergram +Xposed module for removing sponsored messages in Telegram. -An Android Xposed module to remove sponsored messages of Telegram. +Also allows you to copy or save messages when "Restrict saving content" is enabled. +Forwarding messages is still not working due to server limitation. -Also allows you to copy or save messages when "Restrict saving content" is enabled. Forwarding messages is still not working due to server limitation. +## Supported clients +These clients were successfully tested with Killergram enabled. -### Support clients +| Name | Package | Notes | +|:--------------:|:--------------------------------|:-------------| +| Official | `org.telegram.messenger` | | +| Official | `org.telegram.messenger.web` | | +| Official | `org.telegram.messenger.beta` | | +| Nekogram X | `nekox.messenger` | | +| Forkgram | `org.forkclient.messenger` | | +| Forkgram | `org.forkclient.messenger.beta` | | +| exteraGram | `com.exteragram.messenger` | | +| exteraGram | `com.exteragram.messenger.beta` | | +| MDGram | `org.telegram.mdgram` | Only AdBlock | +| MDGram | `org.telegram.mdgramyou` | Only AdBlock | +| BGram | `org.telegram.BifToGram` | | +| Catogram | `ua.itaysonlab.messenger` | | +| Catogram X | `org.nift4.catox` | | +| Nullgram | `top.qwq2333.nullgram` | | +| Nanogram | `com.cool2645.nekolite` | | +| Ninjagram | `me.ninjagram.messenger` | | +| Ninjagram | `org.ninjagram.messenger` | | +| Graph | `ir.ilmili.telegraph` | | +| Plus Messenger | `org.telegram.plus` | | +| iMe Messenger | `com.iMe.android` | | +| aka | `org.aka.messenger` | | +| TurboTel Pro | `ellipi.messenger` | | +| MercuryGram | `belloworld.mercurygram` | | -- **Official** org.telegram.messenger -- **Official** org.telegram.messenger.web -- **Official** org.telegram.messenger.beta -- **NekoX** nekox.messenger -- **Nanogram** com.cool2645.nekolite -- **Plus Messenger** org.telegram.plus -- **iMe Messenger** com.iMe.android -- **BGram** org.telegram.BifToGram -- **Catogram** ua.itaysonlab.messenger -- **Forkgram** org.forkclient.messenger -- **Forkgram** org.forkclient.messenger.beta -- **aka** org.aka.messenger -- **TurboTel Pro** ellipi.messenger -- **Catogram X** org.nift4.catox -- **OwlGram** it.owlgram.android -## License +## Unsupported clients +These mods have a built-in Xposed protection +which is *impossible* to bypass. + +| Name | Package | +|:--------:|:-----------------------| +| Nekogram | `tw.nekomimi.nekogram` | +| OwlGram | `it.owlgram.android` | -This project is licensed under the [GNU General Public Licence, version 3](https://choosealicense.com/licenses/gpl-3.0/). +## License +This project is licensed under the +[GNU General Public Licence, version 3](https://www.gnu.org/licenses/gpl-3.0.txt). diff --git a/app/build.gradle b/app/build.gradle index eebd7d0..e9a17fa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,12 +3,12 @@ plugins { } android { - compileSdk 31 + compileSdk 33 defaultConfig { applicationId "com.shatyuka.killergram" minSdk 16 - targetSdk 31 + targetSdk 33 versionCode appVerCode.toInteger() versionName appVerName } @@ -25,6 +25,7 @@ android { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.debug } } compileOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2441677..e9a5c60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,9 +4,7 @@ + android:label="@string/app_name"> hookPackages = Arrays.asList( "org.telegram.messenger", "org.telegram.messenger.web", "org.telegram.messenger.beta", "nekox.messenger", + "org.forkclient.messenger", + "org.forkclient.messenger.beta", + "com.exteragram.messenger", + "com.exteragram.messenger.beta", + "org.telegram.mdgram", + "org.telegram.mdgramyou", + "org.telegram.BifToGram", + "ua.itaysonlab.messenger", + "org.nift4.catox", + "top.qwq2333.nullgram", "com.cool2645.nekolite", + "me.ninjagram.messenger", + "org.ninjagram.messenger", + "ir.ilmili.telegraph", "org.telegram.plus", "com.iMe.android", - "org.telegram.BifToGram", - "ua.itaysonlab.messenger", - "org.forkclient.messenger", - "org.forkclient.messenger.beta", "org.aka.messenger", "ellipi.messenger", - "org.nift4.catox", - "it.owlgram.android"); + "it.belloworld.mercurygram" + ); @Override - public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) { - if (hookPackages.contains(lpparam.packageName)) { - try { - Class messagesControllerClass = XposedHelpers.findClassIfExists("org.telegram.messenger.MessagesController", lpparam.classLoader); - if (messagesControllerClass != null) { - XposedBridge.hookAllMethods(messagesControllerClass, "getSponsoredMessages", XC_MethodReplacement.returnConstant(null)); - XposedBridge.hookAllMethods(messagesControllerClass, "isChatNoForwards", XC_MethodReplacement.returnConstant(false)); - } - Class chatUIActivityClass = XposedHelpers.findClassIfExists("org.telegram.ui.ChatActivity", lpparam.classLoader); - if (chatUIActivityClass != null) { - XposedBridge.hookAllMethods(chatUIActivityClass, "addSponsoredMessages", XC_MethodReplacement.returnConstant(null)); - } - Class SharedConfigClass = XposedHelpers.findClassIfExists("org.telegram.messenger.SharedConfig", lpparam.classLoader); - if (SharedConfigClass != null) { - XposedBridge.hookAllMethods(SharedConfigClass, "getDevicePerformanceClass", XC_MethodReplacement.returnConstant(2)); - } - Class UserConfigClass = XposedHelpers.findClassIfExists("org.telegram.messenger.UserConfig", lpparam.classLoader); - if (UserConfigClass != null) { - XposedBridge.hookAllMethods(UserConfigClass, "getMaxAccountCount", XC_MethodReplacement.returnConstant(999)); - XposedBridge.hookAllMethods(UserConfigClass, "hasPremiumOnAccounts", XC_MethodReplacement.returnConstant(true)); - } - } catch (Throwable ignored) { - } - } + public void handleLoadPackage(final LoadPackageParam lpparam) { + + if (!hookPackages.contains(lpparam.packageName)) return; + + XposedClass messagesController = new XposedClass("org.telegram.messenger.MessagesController", lpparam.classLoader); + messagesController.hookAllMethods("getSponsoredMessages", XC_MethodReplacement.returnConstant(null)); + messagesController.hookAllMethods("isChatNoForwards", XC_MethodReplacement.returnConstant(false)); + + XposedClass chatUIActivity = new XposedClass("org.telegram.ui.ChatActivity", lpparam.classLoader); + chatUIActivity.hookAllMethods("addSponsoredMessages", XC_MethodReplacement.returnConstant(null)); + + XposedClass sponsoredMessages = new XposedClass("org.telegram.tgnet.TLRPC$messages_SponsoredMessages", lpparam.classLoader); + sponsoredMessages.hookAllMethods("TLdeserialize", XC_MethodReplacement.returnConstant(null)); + + XposedClass getSponsoredMessages = new XposedClass("org.telegram.tgnet.TLRPC$TL_channels_getSponsoredMessages", lpparam.classLoader); + getSponsoredMessages.hookAllMethods("a", XC_MethodReplacement.returnConstant(null)); + + XposedClass chat = new XposedClass("org.telegram.tgnet.TLRPC$Chat", lpparam.classLoader); + chat.hookAllMethods("TLdeserialize", new NoForwardsHook(false)); + + XposedClass sharedConfig = new XposedClass("org.telegram.messenger.SharedConfig", lpparam.classLoader); + sharedConfig.hookAllMethods("getDevicePerformanceClass", XC_MethodReplacement.returnConstant(2)); + + XposedClass userConfig = new XposedClass("org.telegram.messenger.UserConfig", lpparam.classLoader); + userConfig.hookAllMethods("getMaxAccountCount", XC_MethodReplacement.returnConstant(999)); + userConfig.hookAllMethods("hasPremiumOnAccounts", XC_MethodReplacement.returnConstant(true)); } } diff --git a/app/src/main/java/com/shatyuka/killergram/NoForwardsHook.java b/app/src/main/java/com/shatyuka/killergram/NoForwardsHook.java new file mode 100644 index 0000000..d354631 --- /dev/null +++ b/app/src/main/java/com/shatyuka/killergram/NoForwardsHook.java @@ -0,0 +1,26 @@ +package com.shatyuka.killergram; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +public class NoForwardsHook extends XC_MethodHook { + + boolean forConstructor; + + public NoForwardsHook(boolean forConstructor) { + super(); + this.forConstructor = forConstructor; + } + + @Override + protected void afterHookedMethod(MethodHookParam param) { + try { + Object obj = this.forConstructor ? param.thisObject : param.getResult(); + XposedHelpers.setBooleanField(obj, "noforwards", false); + } + catch (Throwable t) { + XposedBridge.log(t); + } + } +} diff --git a/app/src/main/java/com/shatyuka/killergram/XposedClass.java b/app/src/main/java/com/shatyuka/killergram/XposedClass.java new file mode 100644 index 0000000..5d34c7c --- /dev/null +++ b/app/src/main/java/com/shatyuka/killergram/XposedClass.java @@ -0,0 +1,24 @@ +package com.shatyuka.killergram; + +import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; +import de.robv.android.xposed.XposedHelpers; + +public class XposedClass { + + private final Class aClass; + + public XposedClass(String className, ClassLoader loader) { + aClass = XposedHelpers.findClassIfExists(className, loader); + } + + public void hookAllMethods(String methodName, XC_MethodHook callback) { + try { + if (aClass == null) return; + XposedBridge.hookAllMethods(aClass, methodName, callback); + } + catch (Throwable t) { + XposedBridge.log(t); + } + } +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d1..0000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 07d5da9..0000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index eca70cf..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index eca70cf..0000000 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index c209e78..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp deleted file mode 100644 index b2dfe3d..0000000 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp deleted file mode 100644 index 4f0f1d6..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp deleted file mode 100644 index 62b611d..0000000 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp deleted file mode 100644 index 948a307..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 1b9a695..0000000 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp deleted file mode 100644 index 28d4b77..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9287f50..0000000 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index aa7d642..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 9126ae3..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index eab8d90..f105705 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -5,13 +5,25 @@ org.telegram.messenger.web org.telegram.messenger.beta nekox.messenger + org.forkclient.messenger + org.forkclient.messenger.beta + com.exteragram.messenger + com.exteragram.messenger.beta + org.telegram.mdgram + org.telegram.mdgramyou + org.telegram.BifToGram + ua.itaysonlab.messenger + org.nift4.catox + top.qwq2333.nullgram com.cool2645.nekolite + me.ninjagram.messenger + org.ninjagram.messenger + ir.ilmili.telegraph org.telegram.plus com.iMe.android - org.telegram.BifToGram - ua.itaysonlab.messenger - org.forkclient.messenger.beta org.aka.messenger ellipi.messenger + it.belloworld.mercurygram + diff --git a/build.gradle b/build.gradle index f320413..de0c8f8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.2' + classpath 'com.android.tools.build:gradle:7.4.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle.properties b/gradle.properties index 7ce2087..61229c0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,11 +12,11 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true # AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app"s APK +# Android operating system, and which are packaged with your app's APK # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true -appVerName=22.03.12 -appVerCode=202203120 +appVerName=23.04.13 +appVerCode=202304130 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0f04ad0..ca3857d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Nov 10 00:14:21 CST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME