├── .github └── workflows │ └── android.yml ├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── fan │ │ └── soulkiller │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── xposed_init │ ├── java │ │ └── com │ │ │ └── fan │ │ │ └── soulkiller │ │ │ ├── MainActivity.java │ │ │ ├── MainHook.java │ │ │ ├── activity │ │ │ └── DonateActivity.java │ │ │ ├── domain │ │ │ └── LatestReleaseResponse.java │ │ │ ├── fragment │ │ │ └── MySettingsFragment.java │ │ │ ├── hooks │ │ │ ├── ChatHook.java │ │ │ ├── CommentAdHook.java │ │ │ ├── Hooks.java │ │ │ ├── IHook.java │ │ │ ├── SettingHook.java │ │ │ ├── SplashAdHook.java │ │ │ ├── SquareAdHook.java │ │ │ ├── VideoHook.java │ │ │ └── VoiceHook.java │ │ │ └── utils │ │ │ └── Helper.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── dialog_layout.xml │ │ └── donate.xml │ │ ├── mipmap-anydpi-v26 │ │ └── ic_launcher.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_monochrome.png │ │ ├── values-night │ │ └── themes.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ ├── data_extraction_rules.xml │ │ └── perferences.xml │ └── test │ └── java │ └── com │ └── fan │ └── soulkiller │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | if: ${{ !startsWith(github.event.head_commit.message, '[skip ci]') }} 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | submodules: 'recursive' 16 | - name: Setup JDK 11 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 11 20 | - name: Retrieve version 21 | run: | 22 | echo VERSION=$(echo ${{ github.event.head_commit.id }} | head -c 10) >> $GITHUB_ENV 23 | - name: Write key 24 | if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' 25 | run: | 26 | if [ ! -z "${{ secrets.KEY_STORE }}" ]; then 27 | echo releaseStorePassword='${{ secrets.KEY_STORE_PASSWORD }}' >> gradle.properties 28 | echo releaseKeyAlias='${{ secrets.ALIAS }}' >> gradle.properties 29 | echo releaseKeyPassword='${{ secrets.KEY_PASSWORD }}' >> gradle.properties 30 | echo releaseStoreFile='key.jks' >> gradle.properties 31 | echo ${{ secrets.KEY_STORE }} | base64 --decode > key.jks 32 | fi 33 | - name: Build with Gradle 34 | run: bash ./gradlew assembleRelease 35 | - name: Upload built apk 36 | if: success() 37 | uses: actions/upload-artifact@v2 38 | with: 39 | name: LuoS_${{ env.VERSION }} 40 | path: ${{ github.workspace }}/app/build/outputs/apk/release 41 | 42 | skipped: 43 | runs-on: ubuntu-latest 44 | if: ${{ startsWith(github.event.head_commit.message, '[skip ci]') }} 45 | steps: 46 | - uses: actions/checkout@v2 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | .DS_Store 12 | /build 13 | /captures 14 | .externalNativeBuild 15 | .cxx 16 | local.properties 17 | /app/release -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LuoS 2 | Soul App增强助手 3 | ## 停止维护了 4 | 相关release已删除 5 | 6 | ## 功能 7 | - 语音匹配直接查看对面身份 8 | - 去开屏广告 9 | - 去广场广告 10 | - 去瞬间评论区广告 11 | 12 | ## 适配版本 13 | 4.67.0 14 | 15 | ## 使用说明 16 | 1. 下载安装本模块 17 | 2. 在LSPosed中激活本模块 18 | 3. 打开本模块进行设置 19 | 4. 重启Soul App 20 | 5. Enjoy 21 | 22 | 23 | ## 下载 24 | [Github Release](https://github.com/ChengmingFan/LuoS/releases) 25 | 26 | ## 鸣谢 27 | [Xposed](https://github.com/rovo89/Xposed) 28 | [icon kitchen](https://icon.kitchen/) 29 | [Zhiliao](https://github.com/shatyuka/Zhiliao) 30 | 31 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | } 4 | apply plugin: 'idea' 5 | android { 6 | namespace 'com.fan.soulkiller' 7 | compileSdk 33 8 | 9 | defaultConfig { 10 | applicationId "com.fan.soulkiller" 11 | minSdk 29 12 | targetSdk 33 13 | versionCode appVerCode.toInteger() 14 | versionName appVerName 15 | 16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 17 | } 18 | 19 | if (project.hasProperty('releaseStoreFile')) { 20 | signingConfigs { 21 | config { 22 | storeFile = file(project.properties['releaseStoreFile']) 23 | storePassword = project.properties['releaseStorePassword'] 24 | keyAlias = project.properties['releaseKeyAlias'] 25 | keyPassword = project.properties['releaseKeyPassword'] 26 | } 27 | } 28 | } 29 | applicationVariants.all { variant -> 30 | variant.resValue "string", "app_version", variant.versionName 31 | variant.outputs.all { output -> 32 | if (variant.buildType.name == 'release') { 33 | outputFileName = "LuoS_${defaultConfig.versionName}.apk" 34 | } 35 | } 36 | } 37 | 38 | buildTypes { 39 | all { 40 | if (project.hasProperty('releaseStoreFile')) { 41 | signingConfig signingConfigs.config 42 | } else { 43 | println("using debug sign") 44 | signingConfig signingConfigs.debug 45 | } 46 | } 47 | release { 48 | minifyEnabled true 49 | shrinkResources true 50 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 51 | externalNativeBuild { 52 | cmake { 53 | cppFlags "-flto", "-ffunction-sections", "-fdata-sections", "-Wl,--gc-sections", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-Wl,--exclude-libs,ALL" 54 | cFlags "-flto", "-ffunction-sections", "-fdata-sections", "-Wl,--gc-sections", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables", "-Wl,--exclude-libs,ALL" 55 | arguments "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_CXX_FLAGS_RELEASE=-Oz -DNDEBUG", "-DCMAKE_C_FLAGS_RELEASE=-Oz -DNDEBUG" 56 | } 57 | } 58 | } 59 | debug { 60 | externalNativeBuild { 61 | cmake { 62 | arguments "-DCMAKE_CXX_FLAGS_DEBUG=-Og", "-DCMAKE_C_FLAGS_DEBUG=-Og" 63 | } 64 | } 65 | } 66 | } 67 | compileOptions { 68 | sourceCompatibility JavaVersion.VERSION_11 69 | targetCompatibility JavaVersion.VERSION_11 70 | } 71 | } 72 | 73 | dependencies { 74 | implementation fileTree(dir: 'libs', include: ['*.jar']) 75 | compileOnly 'de.robv.android.xposed:api:82' 76 | 77 | implementation("com.squareup.okhttp3:okhttp:4.10.0") 78 | implementation 'androidx.preference:preference:1.2.0' 79 | implementation 'com.google.code.gson:gson:2.10.1' 80 | implementation 'androidx.appcompat:appcompat:1.4.1' 81 | implementation 'com.google.android.material:material:1.6.0' 82 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 83 | testImplementation 'junit:junit:4.13.2' 84 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 85 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 86 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -keep public class com.fan.soulkiller.MainHook 23 | -repackageclasses "soulkiller" 24 | -allowaccessmodification 25 | -overloadaggressively -------------------------------------------------------------------------------- /app/src/androidTest/java/com/fan/soulkiller/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.fan.soulkiller", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 16 | 17 | 20 | 23 | 26 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/assets/xposed_init: -------------------------------------------------------------------------------- 1 | com.fan.soulkiller.MainHook -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.util.Log; 8 | 9 | import androidx.appcompat.app.AppCompatActivity; 10 | import androidx.preference.Preference; 11 | 12 | import com.fan.soulkiller.domain.LatestReleaseResponse; 13 | import com.fan.soulkiller.fragment.MySettingsFragment; 14 | import com.google.gson.Gson; 15 | 16 | import java.io.IOException; 17 | 18 | import okhttp3.OkHttpClient; 19 | import okhttp3.Request; 20 | import okhttp3.Response; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | MySettingsFragment mySettingsFragment = new MySettingsFragment(); 29 | if (savedInstanceState == null) { 30 | getSupportFragmentManager() 31 | .beginTransaction() 32 | .replace(android.R.id.content, mySettingsFragment) 33 | .commit(); 34 | } 35 | try { 36 | getSharedPreferences("com.fan.soulkiller_preferences", Context.MODE_WORLD_READABLE); 37 | } catch (SecurityException e) { 38 | e.printStackTrace(); 39 | } 40 | assembleLatestVersion(mySettingsFragment); 41 | } 42 | 43 | private void assembleLatestVersion(MySettingsFragment mySettingsFragment) { 44 | new Thread(() -> { 45 | OkHttpClient okHttpClient = new OkHttpClient(); 46 | Request request = new Request.Builder().url(getResources().getString(R.string.latest_version)).build(); 47 | try (Response response = okHttpClient.newCall(request).execute()) { 48 | LatestReleaseResponse latestReleaseResponse = new Gson().fromJson(response.body().string(), LatestReleaseResponse.class); 49 | String name = latestReleaseResponse.getName(); 50 | if (name == null) { 51 | return; 52 | } 53 | String latestVersion = name.split(" ")[1].substring(1); 54 | new Handler(Looper.getMainLooper()).post(() -> { 55 | Preference preferenceVersion = mySettingsFragment.findPreference("preference_version"); 56 | assert preferenceVersion != null; 57 | if (!latestVersion.equals(getString(R.string.app_version_str))) { 58 | preferenceVersion.setSummary(String.format("%s (最新版: %s)", getString(R.string.app_version_str), latestVersion)); 59 | } 60 | }); 61 | Log.d("LuoS", "assembleLatestVersion: " + latestVersion); 62 | } catch (IOException exception) { 63 | throw new RuntimeException("Failed to fetch latest version"); 64 | } 65 | }).start(); 66 | 67 | } 68 | 69 | 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/MainHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller; 2 | 3 | import android.app.Application; 4 | import android.widget.Toast; 5 | 6 | import com.fan.soulkiller.hooks.Hooks; 7 | import com.fan.soulkiller.utils.Helper; 8 | 9 | import de.robv.android.xposed.IXposedHookLoadPackage; 10 | import de.robv.android.xposed.IXposedHookZygoteInit; 11 | import de.robv.android.xposed.XC_MethodHook; 12 | import de.robv.android.xposed.XSharedPreferences; 13 | import de.robv.android.xposed.XposedHelpers; 14 | import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; 15 | 16 | /** 17 | * Created by Chengming Fan on 2023/2/25 9:30 PM 18 | */ 19 | public class MainHook implements IXposedHookLoadPackage, IXposedHookZygoteInit { 20 | @Override 21 | public void handleLoadPackage(LoadPackageParam loadPackageParam) throws Throwable { 22 | if (loadPackageParam.packageName.equals("cn.soulapp.android")) { 23 | XposedHelpers.findAndHookMethod(android.app.Instrumentation.class, "callApplicationOnCreate", Application.class, new XC_MethodHook() { 24 | @Override 25 | protected void afterHookedMethod(MethodHookParam param) { 26 | if (param.args[0] instanceof Application) { 27 | Helper.context = ((Application) param.args[0]).getApplicationContext(); 28 | 29 | if (!Helper.init(loadPackageParam.classLoader)) { 30 | Helper.toast("LuoS初始化失败,可能不支持当前版本Soul: " + Helper.packageInfo.versionName, Toast.LENGTH_SHORT); 31 | }else { 32 | Hooks.init(loadPackageParam.classLoader); 33 | Helper.toast("LuoS初始成功", Toast.LENGTH_SHORT); 34 | } 35 | } 36 | } 37 | }); 38 | 39 | } 40 | } 41 | 42 | @Override 43 | public void initZygote(StartupParam startupParam) throws Throwable { 44 | Helper.prefs = new XSharedPreferences("com.fan.soulkiller"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/activity/DonateActivity.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.activity; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.ImageView; 12 | import android.widget.Toast; 13 | 14 | import androidx.annotation.Nullable; 15 | import androidx.appcompat.app.AppCompatActivity; 16 | 17 | import com.fan.soulkiller.R; 18 | 19 | import java.net.URLEncoder; 20 | 21 | /** 22 | * Created by Chengming Fan on 2023/3/10 13:16 23 | */ 24 | public class DonateActivity extends AppCompatActivity implements View.OnClickListener { 25 | private Button alipayBtn; 26 | private Button wechatPayBtn; 27 | 28 | private final static String ALIPAY_LINK = "https://qr.alipay.com"; 29 | 30 | @SuppressLint("MissingInflatedId") 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.donate); 35 | initViews(); 36 | initEvent(); 37 | } 38 | 39 | private void initViews() { 40 | alipayBtn = findViewById(R.id.alipayBtn); 41 | wechatPayBtn = findViewById(R.id.wechatPayBtn); 42 | } 43 | 44 | private void initEvent() { 45 | alipayBtn.setOnClickListener(this); 46 | wechatPayBtn.setOnClickListener(this); 47 | } 48 | 49 | @SuppressLint("NonConstantResourceId") 50 | @Override 51 | public void onClick(View view) { 52 | switch (view.getId()) { 53 | case R.id.alipayBtn: 54 | openAlipay(); 55 | break; 56 | case R.id.wechatPayBtn: 57 | openWechatPay(); 58 | break; 59 | default: 60 | break; 61 | } 62 | } 63 | 64 | private void openAlipay() { 65 | if (openAlipayPayPage(this, ALIPAY_LINK)) { 66 | Toast.makeText(this, "跳转成功", Toast.LENGTH_SHORT).show(); 67 | } else { 68 | Toast.makeText(this, "跳转失败", Toast.LENGTH_SHORT).show(); 69 | } 70 | } 71 | private void openWechatPay() { 72 | Dialog dialog = new Dialog(DonateActivity.this); 73 | dialog.setContentView(R.layout.dialog_layout); 74 | dialog.setCanceledOnTouchOutside(true); 75 | ImageView imageView = dialog.findViewById(R.id.wechatPayImage); 76 | imageView.setOnClickListener(it-> dialog.cancel()); 77 | dialog.show(); 78 | } 79 | 80 | public static boolean openAlipayPayPage(Context context, String qrcode) { 81 | try { 82 | qrcode = URLEncoder.encode(qrcode, "utf-8"); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | try { 87 | final String alipayqr = "alipayqr://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=" + qrcode; 88 | openUri(context, alipayqr + "%3F_s%3Dweb-other&_t=" + System.currentTimeMillis()); 89 | return true; 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | return false; 94 | 95 | } 96 | 97 | private static void openUri(Context context, String s) { 98 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(s)); 99 | context.startActivity(intent); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/domain/LatestReleaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.domain; 2 | 3 | /** 4 | * Created by Chengming Fan on 2023/3/6 15:36 5 | */ 6 | public class LatestReleaseResponse { 7 | private String url; 8 | private String name; 9 | private String tagName; 10 | 11 | public String getUrl() { 12 | return url; 13 | } 14 | 15 | public void setUrl(String url) { 16 | this.url = url; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void setName(String name) { 24 | this.name = name; 25 | } 26 | 27 | public String getTagName() { 28 | return tagName; 29 | } 30 | 31 | public void setTagName(String tagName) { 32 | this.tagName = tagName; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/fragment/MySettingsFragment.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.fragment; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | 7 | import androidx.preference.Preference; 8 | import androidx.preference.PreferenceFragmentCompat; 9 | 10 | import com.fan.soulkiller.R; 11 | 12 | import java.util.Objects; 13 | 14 | /** 15 | * Created by Chengming Fan on 2023/2/26 12:16 AM 16 | */ 17 | public class MySettingsFragment extends PreferenceFragmentCompat { 18 | 19 | @Override 20 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 21 | setPreferencesFromResource(R.xml.perferences, rootKey); 22 | Preference preferenceSourcecode = this.getPreferenceScreen().findPreference("preference_sourcecode"); 23 | Objects.requireNonNull(preferenceSourcecode).setOnPreferenceClickListener(it -> { 24 | Uri uri_sourcecode = Uri.parse("https://github.com/ChengmingFan/LuoS"); 25 | Intent intent_sourcecode = new Intent(Intent.ACTION_VIEW, uri_sourcecode); 26 | startActivity(intent_sourcecode); 27 | return false; 28 | }); 29 | Preference preferenceDonate = this.getPreferenceScreen().findPreference("preference_donate"); 30 | Objects.requireNonNull(preferenceDonate).setOnPreferenceClickListener(it -> { 31 | Intent intent = new Intent("donate_action"); 32 | intent.addCategory("donate_category"); 33 | startActivity(intent); 34 | return false; 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/ChatHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.widget.TextView; 4 | 5 | import java.lang.reflect.Field; 6 | import java.util.List; 7 | 8 | import de.robv.android.xposed.XC_MethodHook; 9 | import de.robv.android.xposed.XposedBridge; 10 | import de.robv.android.xposed.XposedHelpers; 11 | 12 | /** 13 | * Created by Chengming Fan on 2023/8/8 14:45 14 | */ 15 | public class ChatHook implements IHook { 16 | private ClassLoader classLoader; 17 | @Override 18 | public String getName() { 19 | return "聊天"; 20 | } 21 | 22 | @Override 23 | public void init(ClassLoader classLoader) throws Throwable { 24 | this.classLoader = classLoader; 25 | } 26 | 27 | @Override 28 | public void hook() throws ClassNotFoundException { 29 | 30 | XposedHelpers.findAndHookMethod("cn.soulapp.android.lib.common.bean.ChatLimitModel", classLoader, "isLimit", new XC_MethodHook() { 31 | @Override 32 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 33 | super.beforeHookedMethod(param); 34 | } 35 | @Override 36 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 37 | super.afterHookedMethod(param); 38 | XposedBridge.log("送礼物才能私聊? 去你的!"); 39 | param.setResult(false); 40 | } 41 | }); 42 | 43 | 44 | // XposedHelpers.findAndHookMethod("cn.soulapp.android.component.chat.widget.PromptText", 45 | // classLoader, 46 | // "i", 47 | // classLoader.loadClass("cn.soulapp.imlib.msg.ImMessage"), 48 | // classLoader.loadClass("cn.soulapp.android.component.chat.widget.PromptText$a"), 49 | // new XC_MethodHook() { 50 | // @Override 51 | // protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 52 | // super.beforeHookedMethod(param); 53 | // } 54 | // @Override 55 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 56 | // super.afterHookedMethod(param); 57 | // } 58 | // }); 59 | 60 | 61 | XposedHelpers.findAndHookMethod("cn.soulapp.imlib.msg.chat.ChatMessage", classLoader, "i", new XC_MethodHook() { 62 | @Override 63 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 64 | super.beforeHookedMethod(param); 65 | } 66 | @Override 67 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 68 | super.afterHookedMethod(param); 69 | if (param.getResult().equals(9)) { 70 | param.setResult(1); 71 | } 72 | } 73 | }); 74 | 75 | // XposedHelpers.findAndHookMethod("cn.soulapp.android.component.chat.fragment.MsgFragment", classLoader, "D1", boolean.class, new XC_MethodHook() { 76 | // @Override 77 | // protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 78 | // super.beforeHookedMethod(param); 79 | // param.args[0] = false; 80 | // XposedBridge.log("111"); 81 | // } 82 | // @Override 83 | // protected void afterHookedMethod(MethodHookParam param) throws Throwable { 84 | // super.afterHookedMethod(param); 85 | // } 86 | // }); 87 | 88 | 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/CommentAdHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.util.Log; 4 | 5 | import com.fan.soulkiller.utils.Helper; 6 | 7 | import java.lang.reflect.Field; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import de.robv.android.xposed.XC_MethodHook; 12 | import de.robv.android.xposed.XposedHelpers; 13 | 14 | /** 15 | * Created by Chengming Fan on 2023/3/5 22:09 16 | */ 17 | public class CommentAdHook implements IHook{ 18 | 19 | private static final String TAG = "LuoS_Comment"; 20 | private Class lightAdapterClazz; 21 | private Class viewHolderProviderClazz; 22 | private Class soulUnifiedAdClazz; 23 | private Class postDetailHeaderProviderClazz; 24 | private Class postDetailHeaderProvider$g; 25 | private Class cSqItemDetailAdCommentBindingClazz; 26 | private Class viewClass; 27 | private Class soulUnifiedAdLoaderImplClazz; 28 | private Class adSlotClazz; 29 | private Class unifiedAdCacheApiClazz; 30 | 31 | @Override 32 | public String getName() { 33 | return "评论区广告"; 34 | } 35 | 36 | @Override 37 | public void init(ClassLoader classLoader) throws Throwable { 38 | lightAdapterClazz = classLoader.loadClass("com.lufficc.lightadapter.LightAdapter"); 39 | viewHolderProviderClazz = classLoader.loadClass("vy.g"); 40 | soulUnifiedAdClazz = classLoader.loadClass("q3.a"); 41 | postDetailHeaderProviderClazz = classLoader.loadClass("cn.soulapp.android.component.square.post.base.detail.PostDetailHeaderProvider"); 42 | postDetailHeaderProvider$g = classLoader.loadClass("cn.soulapp.android.component.square.post.base.detail.PostDetailHeaderProvider$g"); 43 | cSqItemDetailAdCommentBindingClazz = classLoader.loadClass("cn.soulapp.android.component.square.databinding.CSqItemDetailAdCommentBinding"); 44 | viewClass = classLoader.loadClass("android.view.View"); 45 | soulUnifiedAdLoaderImplClazz = classLoader.loadClass("l4.d"); 46 | adSlotClazz = classLoader.loadClass("l3.a"); 47 | unifiedAdCacheApiClazz = classLoader.loadClass("r5.g"); 48 | } 49 | 50 | @Override 51 | public void hook() throws Throwable { 52 | if (!Helper.prefs.getBoolean("switch_ad", false)) { 53 | return; 54 | } 55 | XposedHelpers.findAndHookMethod(lightAdapterClazz, "y", Class.class, viewHolderProviderClazz, new XC_MethodHook() { 56 | @Override 57 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 58 | if (soulUnifiedAdClazz.isInstance(param.args[0])) { 59 | param.setResult(null); 60 | } 61 | } 62 | }); 63 | 64 | XposedHelpers.findAndHookMethod(postDetailHeaderProviderClazz, "a0", soulUnifiedAdClazz, postDetailHeaderProvider$g, new XC_MethodHook() { 65 | @Override 66 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 67 | param.args[0] = null; 68 | super.beforeHookedMethod(param); 69 | } 70 | }); 71 | 72 | XposedHelpers.findAndHookMethod(cSqItemDetailAdCommentBindingClazz, "bind", viewClass, new XC_MethodHook() { 73 | @Override 74 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 75 | param.setResult(null); 76 | } 77 | }); 78 | 79 | XposedHelpers.findAndHookMethod(soulUnifiedAdLoaderImplClazz, "loadAds", new XC_MethodHook() { 80 | @Override 81 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 82 | Object soulUnifiedAdLoader = param.thisObject; 83 | Field adSlotField = soulUnifiedAdLoaderImplClazz.getDeclaredField("a"); 84 | adSlotField.setAccessible(true); 85 | Object adSlot = adSlotField.get(soulUnifiedAdLoader); 86 | Field aField = adSlotClazz.getDeclaredField("a"); 87 | aField.setAccessible(true); 88 | aField.set(adSlot, "18"); 89 | } 90 | }); 91 | 92 | XposedHelpers.findAndHookMethod(soulUnifiedAdLoaderImplClazz, "h", List.class, new XC_MethodHook() { 93 | @Override 94 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 95 | Log.d(TAG, "beforeHookedMethod: onLoadSuccess"); 96 | param.args[0] = new ArrayList<>(); 97 | } 98 | }); 99 | 100 | XposedHelpers.findAndHookMethod(soulUnifiedAdLoaderImplClazz, "onAdFailed", int.class, String.class, new XC_MethodHook() { 101 | @Override 102 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 103 | Log.d(TAG, "beforeHookedMethod: onAdFailed"); 104 | } 105 | }); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/Hooks.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.widget.Toast; 4 | 5 | import com.fan.soulkiller.utils.Helper; 6 | 7 | import de.robv.android.xposed.XposedBridge; 8 | 9 | /** 10 | * Created by Chengming Fan on 2023/2/25 9:46 PM 11 | */ 12 | public class Hooks { 13 | static final IHook[] defaultHooks = { 14 | new VoiceHook(), 15 | new VideoHook(), 16 | new SplashAdHook(), 17 | new SquareAdHook(), 18 | new CommentAdHook(), 19 | new ChatHook() 20 | }; 21 | 22 | public static void init(final ClassLoader classLoader) { 23 | for (IHook hook : defaultHooks) { 24 | try { 25 | hook.init(classLoader); 26 | hook.hook(); 27 | } catch (Throwable e) { 28 | Helper.toast(hook.getName() + "功能加载失败,可能不支持当前版本Soul: " + Helper.packageInfo.versionName, Toast.LENGTH_LONG); 29 | XposedBridge.log("[SoulKiller] " + e); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/IHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | public interface IHook { 4 | String TAG = "LuoS_TAG"; 5 | String getName(); 6 | void init(final ClassLoader classLoader) throws Throwable; 7 | void hook() throws Throwable; 8 | } -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/SettingHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | /** 4 | * Created by Chengming Fan on 2023/2/25 10:13 PM 5 | */ 6 | public class SettingHook implements IHook{ 7 | 8 | private Class groupSettingItemViewClazz; 9 | 10 | @Override 11 | public String getName() { 12 | return "设置"; 13 | } 14 | 15 | @Override 16 | public void init(ClassLoader classLoader) throws Throwable { 17 | groupSettingItemViewClazz = classLoader.loadClass("cn.soulapp.android.component.group.view.GroupSettingItemView"); 18 | groupSettingItemViewClazz = classLoader.loadClass("cn.soulapp.android.component.group.view.GroupSettingItemView"); 19 | } 20 | 21 | @Override 22 | public void hook() throws Throwable { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/SplashAdHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.util.Log; 4 | 5 | import com.fan.soulkiller.utils.Helper; 6 | 7 | import java.lang.reflect.Field; 8 | 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XposedHelpers; 11 | 12 | /** 13 | * Created by Chengming Fan on 2023/2/27 11:16 PM 14 | */ 15 | public class SplashAdHook implements IHook{ 16 | Class MainScheduler$onCreate$6Clazz; 17 | Class MainActivityClazz; 18 | 19 | @Override 20 | public String getName() { 21 | return "去开屏广告"; 22 | } 23 | 24 | @Override 25 | public void init(ClassLoader classLoader) throws Throwable { 26 | MainScheduler$onCreate$6Clazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.MainScheduler$onCreate$6"); 27 | MainActivityClazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.MainActivity"); 28 | } 29 | 30 | @Override 31 | public void hook() throws Throwable { 32 | if (!Helper.prefs.getBoolean("switch_ad", false)) { 33 | return; 34 | } 35 | XposedHelpers.findAndHookMethod(MainScheduler$onCreate$6Clazz, "invoke", new XC_MethodHook() { 36 | @Override 37 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 38 | super.beforeHookedMethod(param); 39 | Log.d(TAG, "beforeHookedMethod: MainScheduler$onCreate$6Clazz"); 40 | Field mainSchedulerField = MainScheduler$onCreate$6Clazz.getDeclaredField("this$0"); 41 | mainSchedulerField.setAccessible(true); 42 | Object mainScheduler = mainSchedulerField.get(param.thisObject); 43 | param.setResult(null); 44 | XposedHelpers.callMethod(mainScheduler, "q"); 45 | } 46 | }); 47 | 48 | // 移除切屏时的广告 暂时未实现 49 | XposedHelpers.findAndHookMethod(MainActivityClazz, "doShowAd", new XC_MethodHook() { 50 | @Override 51 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 52 | param.setResult(null); 53 | } 54 | }); 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/SquareAdHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.util.Log; 4 | 5 | import com.fan.soulkiller.utils.Helper; 6 | 7 | import java.lang.reflect.Method; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import de.robv.android.xposed.XC_MethodHook; 12 | import de.robv.android.xposed.XposedHelpers; 13 | 14 | /** 15 | * Created by Chengming Fan on 2023/3/5 21:52 16 | */ 17 | public class SquareAdHook implements IHook{ 18 | Class AdViewProvider$bClazz; 19 | Class AdViewProviderClazz; 20 | Class MainActivityClazz; 21 | Class HeavenFragmentClazz; 22 | Class LayoutInflaterClazz; 23 | Class ViewGroupClazz; 24 | Class ViewClazz; 25 | Class BundleClazz; 26 | Class StagePublisherClazz; 27 | Class SplashAdManagerClazz; 28 | Class HotAdManagerClazz; 29 | private Class adProPostProviderClazz; 30 | private Class adPostViewHolder; 31 | private Class soulUnifiedAdClazz; 32 | private Class cSqItemSquareAdPostV2BindingClazz; 33 | private Class cSqItemSquareAdPostV3BindingClazz; 34 | 35 | @Override 36 | public String getName() { 37 | return "广场广告"; 38 | } 39 | 40 | @Override 41 | public void init(ClassLoader classLoader) throws Throwable { 42 | AdViewProvider$bClazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.AdViewProvider$b"); 43 | AdViewProviderClazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.AdViewProvider"); 44 | MainActivityClazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.MainActivity"); 45 | HeavenFragmentClazz = classLoader.loadClass("cn.soulapp.android.component.startup.main.HeavenFragment"); 46 | LayoutInflaterClazz = classLoader.loadClass("android.view.LayoutInflater"); 47 | ViewGroupClazz = classLoader.loadClass("android.view.ViewGroup"); 48 | ViewClazz = classLoader.loadClass("android.view.View"); 49 | BundleClazz = classLoader.loadClass("android.os.Bundle"); 50 | StagePublisherClazz = classLoader.loadClass("cn.soulapp.android.component.startup.utils.j0"); 51 | SplashAdManagerClazz = classLoader.loadClass("u5.e"); 52 | HotAdManagerClazz = classLoader.loadClass("u5.c"); 53 | adProPostProviderClazz= classLoader.loadClass("cn.soulapp.android.component.square.main.ad.u"); 54 | adPostViewHolder = classLoader.loadClass("cn.soulapp.android.component.square.main.ad.AdPostViewHolder"); 55 | soulUnifiedAdClazz = classLoader.loadClass("q3.a"); 56 | cSqItemSquareAdPostV2BindingClazz = classLoader.loadClass("cn.soulapp.android.component.square.databinding.CSqItemSquareAdPostV2Binding"); 57 | cSqItemSquareAdPostV3BindingClazz = classLoader.loadClass("cn.soulapp.android.component.square.databinding.CSqItemSquareAdPostV3Binding"); 58 | } 59 | 60 | @Override 61 | public void hook() throws Throwable { 62 | if (!Helper.prefs.getBoolean("switch_ad", false)) { 63 | return; 64 | } 65 | XposedHelpers.findAndHookMethod(HeavenFragmentClazz, "onCreateView", LayoutInflaterClazz, ViewGroupClazz, BundleClazz, new XC_MethodHook() { 66 | @Override 67 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 68 | Object obj = XposedHelpers.callStaticMethod(StagePublisherClazz, "b"); 69 | Log.d(TAG, "beforeHookedMethod: onCreateView: " + obj.toString()); 70 | List result = new ArrayList<>(); 71 | if (obj instanceof ArrayList) { 72 | for (Object o : (List) obj) { 73 | result.add((Integer) o); 74 | Log.d(TAG, "beforeHookedMethod: onCreateView: " + (Integer) o); 75 | } 76 | } 77 | Object splashAdManager = XposedHelpers.callStaticMethod(SplashAdManagerClazz, "f"); 78 | Method kMethod = SplashAdManagerClazz.getDeclaredMethod("k"); 79 | kMethod.setAccessible(true); 80 | Object res = kMethod.invoke(splashAdManager); 81 | Log.d(TAG, "beforeHookedMethod: onCreateView: " + res); 82 | } 83 | }); 84 | 85 | XposedHelpers.findAndHookMethod(HotAdManagerClazz, "a", new XC_MethodHook() { 86 | @Override 87 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 88 | super.beforeHookedMethod(param); 89 | param.setResult(null); 90 | } 91 | }); 92 | 93 | XposedHelpers.findAndHookMethod(adProPostProviderClazz, "d", LayoutInflaterClazz, ViewGroupClazz, new XC_MethodHook() { 94 | @Override 95 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 96 | param.setResult(null); 97 | } 98 | }); 99 | 100 | XposedHelpers.findAndHookMethod(cSqItemSquareAdPostV2BindingClazz, "bind", ViewClazz, new XC_MethodHook() { 101 | @Override 102 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 103 | param.setResult(null); 104 | } 105 | }); 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/VideoHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import android.util.Log; 4 | 5 | import com.fan.soulkiller.utils.Helper; 6 | import com.google.gson.Gson; 7 | 8 | import de.robv.android.xposed.IXposedHookLoadPackage; 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XposedBridge; 11 | import de.robv.android.xposed.XposedHelpers; 12 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 13 | 14 | /** 15 | * Created by Chengming Fan on 2023/2/24 11:49 PM 16 | */ 17 | public class VideoHook implements IHook { 18 | Class videoMatchControllerClazz; 19 | Class videoMatchResultClazz; 20 | Class callbackClazz; 21 | 22 | @Override 23 | public String getName() { 24 | return "视频"; 25 | } 26 | 27 | @Override 28 | public void init(ClassLoader classLoader) throws Throwable { 29 | videoMatchControllerClazz = classLoader.loadClass("cn.soulapp.android.component.planet.videomatch.VideoMatchController"); 30 | videoMatchResultClazz = classLoader.loadClass("cn.soulapp.android.component.planet.videomatch.api.bean.VideoMatchResult"); 31 | callbackClazz = classLoader.loadClass("cn.soulapp.android.component.planet.videomatch.VideoMatchController$i"); 32 | } 33 | 34 | @Override 35 | public void hook() throws Throwable { 36 | if (Helper.prefs.getBoolean("switch_video", false)){ 37 | XposedBridge.log("======soul助手(视频模块)开始工作了======"); 38 | XposedHelpers.findAndHookMethod(videoMatchControllerClazz, "O", videoMatchResultClazz, boolean.class, new XC_MethodHook() { 39 | @Override 40 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 41 | Log.d(TAG, "视频匹配成功,尝试消除马赛克"); 42 | Object videoMatchController = XposedHelpers.callStaticMethod(videoMatchControllerClazz, "I"); 43 | XposedHelpers.callMethod(videoMatchController, "k"); 44 | } 45 | }); 46 | 47 | XposedHelpers.findAndHookMethod(callbackClazz, "a", videoMatchResultClazz, new XC_MethodHook() { 48 | @Override 49 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 50 | Log.d(TAG, "正在视频匹配。。。。。。"); 51 | } 52 | }); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/hooks/VoiceHook.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.hooks; 2 | 3 | import com.fan.soulkiller.utils.Helper; 4 | 5 | import de.robv.android.xposed.XC_MethodHook; 6 | import de.robv.android.xposed.XposedBridge; 7 | import de.robv.android.xposed.XposedHelpers; 8 | 9 | /** 10 | * Created by Chengming Fan on 2023/2/24 3:41 PM 11 | */ 12 | 13 | public class VoiceHook implements IHook { 14 | Class managerClazz; 15 | Class matchResultClazz; 16 | Class identityOpenControllerClazz; 17 | @Override 18 | public String getName() { 19 | return "语音"; 20 | } 21 | 22 | @Override 23 | public void init(ClassLoader classLoader) throws Throwable { 24 | managerClazz = classLoader.loadClass("cn.soulapp.android.component.planet.voicematch.utils.CallMatchManager"); 25 | matchResultClazz = classLoader.loadClass("com.soulapp.android.planet.bean.MatchResult"); 26 | identityOpenControllerClazz = classLoader.loadClass("cn.soulapp.android.component.planet.voicematch.model.IdentityOpenController"); 27 | } 28 | 29 | @Override 30 | public void hook() throws Throwable { 31 | if (Helper.prefs.getBoolean("switch_voice", false)) { 32 | XposedBridge.log("======soul助手(语音模块)开始工作了======"); 33 | XposedHelpers.findAndHookMethod(managerClazz, "y", matchResultClazz, int.class, new XC_MethodHook() { 34 | @Override 35 | protected void afterHookedMethod(MethodHookParam param) throws Throwable { 36 | Object identityOpenController = XposedHelpers.callStaticMethod(identityOpenControllerClazz, "c"); 37 | XposedHelpers.callMethod(identityOpenController, "k", false); 38 | } 39 | }); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/fan/soulkiller/utils/Helper.java: -------------------------------------------------------------------------------- 1 | package com.fan.soulkiller.utils; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.pm.PackageInfo; 6 | import android.widget.Toast; 7 | 8 | import de.robv.android.xposed.XSharedPreferences; 9 | import de.robv.android.xposed.XposedBridge; 10 | 11 | /** 12 | * Created by Chengming Fan on 2023/2/25 9:48 PM 13 | */ 14 | public class Helper { 15 | @SuppressLint("StaticFieldLeak") 16 | public static Context context; 17 | public static PackageInfo packageInfo; 18 | public static XSharedPreferences prefs; 19 | 20 | public static boolean init(ClassLoader classLoader) { 21 | try { 22 | packageInfo = context.getPackageManager().getPackageInfo("cn.soulapp.android", 0); 23 | return true; 24 | } catch (Exception e) { 25 | XposedBridge.log("[SoulKiller] " + e); 26 | return false; 27 | } 28 | } 29 | public static void toast(CharSequence text, int duration) { 30 | Toast toast = Toast.makeText(context, "", duration); 31 | toast.setText("LuoS:" + text); 32 | toast.show(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/donate.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |