From 3bc833294702cf6a87dddf694565a13e639478c8 Mon Sep 17 00:00:00 2001 From: kooritea Date: Sat, 24 Oct 2020 16:22:27 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E8=BF=87=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E9=85=8D=E7=BD=AEhook=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 32 ++- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 7 + .../com/kooritea/fcmfix/MainActivity.java | 30 +-- .../java/com/kooritea/fcmfix/XposedMain.java | 11 ++ .../com/kooritea/fcmfix/XposedProvider.java | 85 ++++++++ .../fcmfix/util/ContentProviderHelper.java | 82 ++++++++ .../kooritea/fcmfix/xposed/BroadcastFix.java | 9 +- .../fcmfix/xposed/ReconnectManagerFix.java | 182 +++++++++++++++--- .../kooritea/fcmfix/xposed/XposedModule.java | 14 +- 10 files changed, 387 insertions(+), 69 deletions(-) create mode 100644 app/src/main/java/com/kooritea/fcmfix/XposedProvider.java create mode 100644 app/src/main/java/com/kooritea/fcmfix/util/ContentProviderHelper.java diff --git a/README.md b/README.md index e30db83..1bde0d1 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,35 @@ 使用xposed让被完全停止的应用响应fcm,让fcm送达率达到100%,不错过任何通知 - 允许fcm唤醒选中的应用来发送通知 -- 修复在国内网络下出现重连服务出现负数问题(仅203615037有效) -- 固定心跳间隔为117s(仅203615037有效) +- 修复在国内网络下出现重连服务出现负数问题(可选)(需要查看自己手机上gms的版本编辑配置文件) +- 固定心跳间隔为117s(可选)(需要查看自己手机上gms的版本编辑配置文件) ## 注意 在国内版miui上,除了在本应用中勾选目标应用之外,还要给予目标应用自启动权限中的允许系统唤醒权限(eu版和国际版则不需要给自启动权限) -## todo -没想到版本更新后混淆名称会变,支持多版本的事等之后有空再说吧 \ No newline at end of file +## 由于gms更新较快,代码遭到混淆,hook点几乎每个版本都会变动,所以需要手动修改配置文件 +- 1. 确保xposed模块已经运行,如果存在/data/data/com.google.andorid.gms/shared_prefs/fcmfix_config.xml则证明模块已经成功运行,这是配置文件,之后都是编辑这个文件的内容。 +- 2. 下载MT管理器等可以进行反编译的工具 +- 3. 对/data/app/com.google.android.gms-/base.apk进行反编译(在MT管理器对apk文件选择查看,点击classes.dex使用Dex编辑器++打开,全选 -> 确认) +- 4. 搜索 "Previous alarms will stay active" ,路径: / ,搜索类型: 代码,按道理应该只有一个搜索结果,将搜到类名(一般是4个字母)填入配置文件的timer_class项中 +- 5. 回到MT管理器点击刚才搜索到的类,看文件最上面第九行左右开始属性声明,`.field private final d:Landroid/content/Intent;`将这个私有属性类型是Intent的属性`d(按自己实际情况填)`填入配置文件的timer_intent_property +- 6. 寻找一个没有返回值,只有一个长整形参数的public方法,一般是第90行左右的`.method public final a(J)V`,认准这个`final`和`(J)`和`V`找这个方法,把方法名`a`填入配置文件的timer_settimeout_method +- 7. 继续查看刚在找到的这个timer_settimeout_method,这个方法往下几行的`iget-wide v0, p0, L[xxxx];->[f]:J`,这个xxxx是最开始的类名,这个f就是我们要找的属性名,将这个找到的属性名`f`填入配置文件的timer_next_time_property +- 8. 修改完上面的配置项,现在配置文件大概是这样的 +```xml + + + + d + f + + a + aazg + 20.39.15 (120400-335085812) + + + +``` +- 9. 最后将配置文件的enable修改true,保存,重启手机 + +- 10. 一般来说gms更新改变的只有类名也就是timer_class \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 82876a8..496e72b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.kooritea.fcmfix" minSdkVersion 27 targetSdkVersion 29 - versionCode 2 - versionName "0.0.2" + versionCode 3 + versionName "0.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b392790..49128f0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,6 +25,13 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/kooritea/fcmfix/MainActivity.java b/app/src/main/java/com/kooritea/fcmfix/MainActivity.java index e00c0ff..6b6b849 100644 --- a/app/src/main/java/com/kooritea/fcmfix/MainActivity.java +++ b/app/src/main/java/com/kooritea/fcmfix/MainActivity.java @@ -4,6 +4,7 @@ import android.annotation.SuppressLint; import android.app.Activity; +import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; @@ -11,10 +12,12 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; +import android.database.ContentObserver; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -26,14 +29,18 @@ import android.widget.ListView; import android.widget.TextView; +import com.kooritea.fcmfix.util.ContentProviderHelper; + import java.io.File; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Observer; import java.util.Set; public class MainActivity extends AppCompatActivity { @@ -161,39 +168,16 @@ public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) appListAdapter.notifyDataSetChanged(); } }); - this.initHeartbeatInterval(); - } - - private void initHeartbeatInterval(){ - if(this.sharedPreferences.getString("heartbeatInterval","").equals("")){ - this.sharedPreferencesEditor.putString("heartbeatInterval","117000"); - this.sharedPreferencesEditor.commit(); - this.setWorldReadable(); - } } private void addAppInAllowList(String packageName){ this.allowList.add(packageName); this.sharedPreferencesEditor.putStringSet("allowList",this.allowList); this.sharedPreferencesEditor.commit(); - this.setWorldReadable(); } private void deleteAppInAllowList(String packageName){ this.allowList.remove(packageName); this.sharedPreferencesEditor.putStringSet("allowList",this.allowList); this.sharedPreferencesEditor.commit(); - this.setWorldReadable(); - } - - private void setWorldReadable() { - File dataDir = new File(getApplicationInfo().dataDir); - File prefsDir = new File(dataDir, "shared_prefs"); - File prefsFile = new File(prefsDir, "config.xml"); - if (prefsFile.exists()) { - for (File file : new File[]{dataDir, prefsDir, prefsFile}) { - file.setReadable(true, false); - file.setExecutable(true, false); - } - } } } \ No newline at end of file diff --git a/app/src/main/java/com/kooritea/fcmfix/XposedMain.java b/app/src/main/java/com/kooritea/fcmfix/XposedMain.java index c569605..7e15205 100644 --- a/app/src/main/java/com/kooritea/fcmfix/XposedMain.java +++ b/app/src/main/java/com/kooritea/fcmfix/XposedMain.java @@ -1,8 +1,17 @@ package com.kooritea.fcmfix; +import android.app.AndroidAppHelper; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + import com.kooritea.fcmfix.xposed.BroadcastFix; import com.kooritea.fcmfix.xposed.ReconnectManagerFix; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; + import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage; @@ -17,6 +26,8 @@ public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageP if(loadPackageParam.packageName.equals("com.google.android.gms")){ XposedBridge.log("[fcmfix] start hook com.google.android.gms"); new ReconnectManagerFix(loadPackageParam); + } + } } diff --git a/app/src/main/java/com/kooritea/fcmfix/XposedProvider.java b/app/src/main/java/com/kooritea/fcmfix/XposedProvider.java new file mode 100644 index 0000000..8c62311 --- /dev/null +++ b/app/src/main/java/com/kooritea/fcmfix/XposedProvider.java @@ -0,0 +1,85 @@ +package com.kooritea.fcmfix; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class XposedProvider extends ContentProvider { + + private static UriMatcher uriMatcher; + + static + { + uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); + uriMatcher.addURI("com.kooritea.fcmfix.provider","config",0); + } + + @Override + public boolean onCreate() { + return false; + } + + @Nullable + @Override + public String getType(@NonNull Uri uri) { + switch (uriMatcher.match(uri)) + { + default: + break; + } + return null; + } + + + @Nullable + @Override + public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) { + //这里填写查询逻辑 + SharedPreferences sharedPreferences = getContext().getSharedPreferences("config", Context.MODE_PRIVATE); + String[] COLUMN_NAME = { "key", "value" }; + MatrixCursor data = new MatrixCursor(COLUMN_NAME); + switch (selection){ + case "heartbeatInterval": + data.addRow(new Object[]{"heartbeatInterval",sharedPreferences.getLong("heartbeatInterval",117000L)}); + break; + case "allowList": + for(String item : sharedPreferences.getStringSet("allowList",new HashSet())){ + data.addRow(new Object[]{"allowList",item}); + } + break; + } + return data; + } + + @Nullable + @Override + public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) { + //这里填写插入逻辑 + return null; + } + + @Override + public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) { + //这里填写更新逻辑 + return 0; + } + + @Override + public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) { + //这里填写删除逻辑 + return 0; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kooritea/fcmfix/util/ContentProviderHelper.java b/app/src/main/java/com/kooritea/fcmfix/util/ContentProviderHelper.java new file mode 100644 index 0000000..6796841 --- /dev/null +++ b/app/src/main/java/com/kooritea/fcmfix/util/ContentProviderHelper.java @@ -0,0 +1,82 @@ +package com.kooritea.fcmfix.util; + +import android.content.ContentResolver; +import android.content.Context; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +public class ContentProviderHelper { + + public ContentResolver contentResolver; + private Uri uri; + private ArrayList contentObservers = new ArrayList<>(); + public Boolean useDefaultValue = false; + + public ContentProviderHelper(Context context, String uri){ + contentResolver = context.getContentResolver(); + this.uri = Uri.parse(uri); + } + public ContentProviderHelper(){ + useDefaultValue = true; + } + + public Long getLong(String selection,Long defaultValue){ + if(useDefaultValue){ + return defaultValue; + } + Cursor cursor = contentResolver.query(uri, null, selection, null,null); + if(cursor == null){ + return defaultValue; + } + cursor.getCount(); + while(cursor.moveToNext()) { + if(selection.equals(cursor.getString(cursor.getColumnIndex("key")))){ + cursor.close(); + return cursor.getLong(cursor.getColumnIndex("value")); + } + } + cursor.close(); + return defaultValue; + } + public String getString(String selection,String defaultValue){ + if(useDefaultValue){ + return defaultValue; + } + Cursor cursor =contentResolver.query(uri, null, selection, null,null); + if(cursor == null){ + return defaultValue; + } + cursor.getCount(); + while(cursor.moveToNext()) { + if(selection.equals(cursor.getString(cursor.getColumnIndex("key")))){ + cursor.close(); + return cursor.getString(cursor.getColumnIndex("value")); + } + } + cursor.close(); + return defaultValue; + } + public Set getStringSet(String selection){ + if(useDefaultValue){ + return new HashSet(); + } + Cursor cursor = contentResolver.query(uri, null, selection, null,null); + if(cursor == null){ + return new HashSet(); + } + cursor.getCount(); + Set result = new HashSet(); + while(cursor.moveToNext()) { + if(selection.equals(cursor.getString(cursor.getColumnIndex("key")))){ + result.add(cursor.getString(cursor.getColumnIndex("value"))); + } + } + cursor.close(); + return result; + } +} diff --git a/app/src/main/java/com/kooritea/fcmfix/xposed/BroadcastFix.java b/app/src/main/java/com/kooritea/fcmfix/xposed/BroadcastFix.java index 3dcfd58..7e59af6 100644 --- a/app/src/main/java/com/kooritea/fcmfix/xposed/BroadcastFix.java +++ b/app/src/main/java/com/kooritea/fcmfix/xposed/BroadcastFix.java @@ -1,8 +1,11 @@ package com.kooritea.fcmfix.xposed; +import android.app.AndroidAppHelper; import android.content.ContextWrapper; import android.content.Intent; +import com.kooritea.fcmfix.util.ContentProviderHelper; + import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; @@ -15,8 +18,12 @@ public class BroadcastFix extends XposedModule { + protected ContentProviderHelper contentProviderHelper; + public BroadcastFix(XC_LoadPackage.LoadPackageParam loadPackageParam) { super(loadPackageParam); + contentProviderHelper = new ContentProviderHelper(AndroidAppHelper.currentApplication().getApplicationContext(),"content://com.kooritea.fcmfix.provider/config"); + this.startHook(); } protected void startHook(){ @@ -58,7 +65,7 @@ protected void beforeHookedMethod(MethodHookParam methodHookParam) throws Throwa private boolean targetIsAllow(String packageName){ if (!packageName.equals("com.tencent.mm")) { - Set allowList = this.getXSharedPreferences().getStringSet("allowList", new HashSet()); + Set allowList = this.contentProviderHelper.getStringSet("allowList"); for (String item : allowList) { if (item.equals(packageName)) { return true; diff --git a/app/src/main/java/com/kooritea/fcmfix/xposed/ReconnectManagerFix.java b/app/src/main/java/com/kooritea/fcmfix/xposed/ReconnectManagerFix.java index c8f0dca..e1a1b8a 100644 --- a/app/src/main/java/com/kooritea/fcmfix/xposed/ReconnectManagerFix.java +++ b/app/src/main/java/com/kooritea/fcmfix/xposed/ReconnectManagerFix.java @@ -1,78 +1,206 @@ package com.kooritea.fcmfix.xposed; import android.app.AndroidAppHelper; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.TaskStackBuilder; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; import android.os.SystemClock; +import android.os.UserManager; +import androidx.core.app.NotificationCompat; +import androidx.core.app.NotificationManagerCompat; + +import com.kooritea.fcmfix.R; +import com.kooritea.fcmfix.util.ContentProviderHelper; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Timer; import java.util.TimerTask; import de.robv.android.xposed.XC_MethodHook; +import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.XposedHelpers; import de.robv.android.xposed.callbacks.XC_LoadPackage; -public class ReconnectManagerFix extends XposedModule{ +import static android.content.Context.NOTIFICATION_SERVICE; + +public class ReconnectManagerFix extends XposedModule { private Class GcmChimeraService; + public ReconnectManagerFix(XC_LoadPackage.LoadPackageParam loadPackageParam) { super(loadPackageParam); + this.startHookGcmServiceStart(); } - protected void startHook(){ - this.GcmChimeraService = XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService",loadPackageParam.classLoader); - XposedHelpers.findAndHookMethod(XposedHelpers.findClass("abcn",loadPackageParam.classLoader),"a", long.class, new XC_MethodHook() { + private void startHookGcmServiceStart() { + this.GcmChimeraService = XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService", loadPackageParam.classLoader); + XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService", loadPackageParam.classLoader), "onCreate", new XC_MethodHook() { + @Override + protected void afterHookedMethod(final MethodHookParam param) throws Throwable { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction("com.kooritea.fcmfix.log"); + AndroidAppHelper.currentApplication().getApplicationContext().registerReceiver(logBroadcastReceive, intentFilter); + if (AndroidAppHelper.currentApplication().getApplicationContext().getSystemService(UserManager.class).isUserUnlocked()) { + try { + startHook(); + printLog("ReconnectManagerFixStartHook 完成"); + } catch (Exception e) { + printLog("ReconnectManagerFixStartHook 初始化失败: " + e.getMessage()); + } + } else { + IntentFilter userUnlockIntentFilter = new IntentFilter(); + userUnlockIntentFilter.addAction(Intent.ACTION_USER_UNLOCKED); + AndroidAppHelper.currentApplication().getApplicationContext().registerReceiver(unlockBroadcastReceive, userUnlockIntentFilter); + } + } + }); + XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService", loadPackageParam.classLoader), "onDestroy", new XC_MethodHook() { + @Override + protected void beforeHookedMethod(final MethodHookParam param) throws Throwable { + AndroidAppHelper.currentApplication().getApplicationContext().unregisterReceiver(logBroadcastReceive); + } + }); + + } + + private void startHook() throws Exception { + Context context = AndroidAppHelper.currentApplication().getApplicationContext(); + final SharedPreferences sharedPreferences = context.getSharedPreferences("fcmfix_config", Context.MODE_PRIVATE); + String versionName = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; + if (!sharedPreferences.getBoolean("isInit", false)) { + this.printLog("fcmfix_config init"); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean("isInit", true); + editor.putBoolean("enable", false); + editor.putLong("heartbeatInterval", 117000L); + editor.putString("timer_class", ""); + editor.putString("timer_settimeout_method", ""); + editor.putString("timer_next_time_property", ""); + editor.putString("timer_intent_property", ""); + editor.putString("gms_version", versionName); + editor.commit(); + this.sendUpdateNotification("[xposed-fcmfix]请初始化fcmfix配置"); + return; + } + if (!sharedPreferences.getBoolean("enable", false)) { + this.printLog("ReconnectManagerFix配置已关闭"); + return; + } + if (!sharedPreferences.getString("gms_version", "").equals(versionName)) { + this.printLog("gms已更新,请重新编辑fcmfix_config.xml"); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean("enable", false); + editor.putString("gms_version", versionName); + editor.commit(); + this.sendUpdateNotification("[xposed-fcmfix]gms已更新"); + return; + } + this.printLog("ReconnectManagerFix读取配置已成功,timer_class: " + sharedPreferences.getString("timer_class", "")); + XposedHelpers.findAndHookMethod(XposedHelpers.findClass(sharedPreferences.getString("timer_class", ""), loadPackageParam.classLoader), sharedPreferences.getString("timer_settimeout_method", ""), long.class, new XC_MethodHook() { @Override protected void beforeHookedMethod(final MethodHookParam param) throws Throwable { // 修改心跳间隔 - Intent intent = (Intent) XposedHelpers.getObjectField(param.thisObject,"d"); - if("com.google.android.gms.gcm.HEARTBEAT_ALARM".equals(intent.getAction())){ - param.args[0] = 117000L; + Intent intent = (Intent) XposedHelpers.getObjectField(param.thisObject, sharedPreferences.getString("timer_intent_property", "")); + if ("com.google.android.gms.gcm.HEARTBEAT_ALARM".equals(intent.getAction())) { + param.args[0] = sharedPreferences.getLong("heartbeatInterval", 117000L); } } + @Override protected void afterHookedMethod(final MethodHookParam param) throws Throwable { // 防止计时器出现负数计时,分别是心跳计时和重连计时 - Intent intent = (Intent) XposedHelpers.getObjectField(param.thisObject,"d"); - if("com.google.android.intent.action.GCM_RECONNECT".equals(intent.getAction()) || "com.google.android.gms.gcm.HEARTBEAT_ALARM".equals(intent.getAction())){ + Intent intent = (Intent) XposedHelpers.getObjectField(param.thisObject, sharedPreferences.getString("timer_intent_property", "")); + if ("com.google.android.intent.action.GCM_RECONNECT".equals(intent.getAction()) || "com.google.android.gms.gcm.HEARTBEAT_ALARM".equals(intent.getAction())) { new Timer("ReconnectManagerFix").schedule(new TimerTask() { @Override public void run() { - long nextConnectionTime = XposedHelpers.getLongField(param.thisObject,"f"); - if(nextConnectionTime !=0 && nextConnectionTime - SystemClock.elapsedRealtime() < 0){ + long nextConnectionTime = XposedHelpers.getLongField(param.thisObject, sharedPreferences.getString("timer_next_time_property", "")); + if (nextConnectionTime != 0 && nextConnectionTime - SystemClock.elapsedRealtime() < 0) { AndroidAppHelper.currentApplication().getApplicationContext().sendBroadcast(new Intent("com.google.android.intent.action.GCM_RECONNECT")); printLog("Send broadcast GCM_RECONNECT"); } } - }, (long)param.args[0]+5000); + }, (long) param.args[0] + 5000); } } }); - XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService",loadPackageParam.classLoader),"onCreate", new XC_MethodHook() { - @Override - protected void afterHookedMethod(final MethodHookParam param) throws Throwable { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction("com.kooritea.fcmfix.log"); - AndroidAppHelper.currentApplication().getApplicationContext().registerReceiver(logBroadcastReceive,intentFilter); - } - }); - XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.google.android.gms.gcm.GcmChimeraService",loadPackageParam.classLoader),"onDestroy", new XC_MethodHook() { - @Override - protected void beforeHookedMethod(final MethodHookParam param) throws Throwable { - AndroidAppHelper.currentApplication().getApplicationContext().unregisterReceiver(logBroadcastReceive); + } + + private void sendUpdateNotification(String text) { + Context context = AndroidAppHelper.currentApplication().getApplicationContext(); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); + this.createFcmfixChannel(notificationManager); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "fcmfix"); + builder.setSmallIcon(R.mipmap.ic_launcher); + builder.setContentTitle(text); + // builder.setContentText("点击编辑fcmfix.xml"); + builder.setAutoCancel(true); + notificationManager.notify((int) System.currentTimeMillis(), builder.build()); + } + + private void createFcmfixChannel(NotificationManager notificationManager) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + List channelList = notificationManager.getNotificationChannels(); + for (NotificationChannel item : channelList) { + if (item.getId() == "fcmfix") { + item.setName("fcmfix"); + item.setImportance(NotificationManager.IMPORTANCE_HIGH); + item.setDescription("fcmfix"); + return; + } } - }); + NotificationChannel channel = new NotificationChannel("fcmfix", "fcmfix", NotificationManager.IMPORTANCE_HIGH); + channel.setDescription("[xposed] fcmfix更新通知"); + notificationManager.createNotificationChannel(channel); + } } private BroadcastReceiver logBroadcastReceive = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if("com.kooritea.fcmfix.log".equals(action)) { - XposedHelpers.callStaticMethod(GcmChimeraService,"a",new Class[]{String.class,Object[].class},"[fcmfix] "+ intent.getStringExtra("text"),null); + if ("com.kooritea.fcmfix.log".equals(action)) { + XposedHelpers.callStaticMethod(GcmChimeraService, "a", new Class[]{String.class, Object[].class}, "[fcmfix] " + intent.getStringExtra("text"), null); + } + } + }; + + private BroadcastReceiver unlockBroadcastReceive = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_UNLOCKED.equals(action)) { + printLog("UserUnlock Broadcast"); + try { + startHook(); + printLog("ReconnectManagerFixStartHook 完成"); + AndroidAppHelper.currentApplication().getApplicationContext().unregisterReceiver(unlockBroadcastReceive); + } catch (Exception e) { + printLog("ReconnectManagerFixStartHook 初始化失败: " + e.getMessage()); + } } } }; diff --git a/app/src/main/java/com/kooritea/fcmfix/xposed/XposedModule.java b/app/src/main/java/com/kooritea/fcmfix/xposed/XposedModule.java index acc06f7..70870fb 100644 --- a/app/src/main/java/com/kooritea/fcmfix/xposed/XposedModule.java +++ b/app/src/main/java/com/kooritea/fcmfix/xposed/XposedModule.java @@ -2,11 +2,10 @@ import android.app.AndroidAppHelper; import android.content.Intent; +import android.util.Log; -import java.lang.reflect.Method; +import com.kooritea.fcmfix.util.ContentProviderHelper; -import de.robv.android.xposed.XSharedPreferences; -import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage; public class XposedModule { @@ -15,15 +14,6 @@ public class XposedModule { protected XposedModule(final XC_LoadPackage.LoadPackageParam loadPackageParam){ this.loadPackageParam = loadPackageParam; - this.startHook(); - } - - protected void startHook(){}; - - protected XSharedPreferences getXSharedPreferences(){ - XSharedPreferences xSharedPreferences = new XSharedPreferences("com.kooritea.fcmfix","config"); - xSharedPreferences.makeWorldReadable(); - return xSharedPreferences; } protected void printLog(String text){