diff --git a/.gitignore b/.gitignore index cb36f0d..5d6783a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,11 @@ *.iml .gradle /local.properties -/gradle.properties /.idea/ .DS_Store build/ /captures .externalNativeBuild -/app/fabric.properties .vscode +build +release \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 26bcf6b..b94a4fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: android +dist: trusty android: components: - tools @@ -6,8 +7,6 @@ android: install: - echo y | sdkmanager "ndk-bundle" script: - - curl -u xausky:$SYSKILLER_TOKEN https://syskiller.org/remote.php/webdav/xausky.jks -o ../xausky.jks - - echo apiSecret=$FABRIC_APP_SECRET > app/fabric.properties - ./gradlew assembleRelease deploy: skip_cleanup: true @@ -18,6 +17,4 @@ deploy: file: app/build/outputs/apk/release/app-release.apk on: tags: true - repo: xausky/UnityModManager -after_success: -- curl -u xausky:$SYSKILLER_TOKEN -T app/build/outputs/apk/release/app-release.apk https://syskiller.org/remote.php/webdav/模组管理器/模组管理器-$TRAVIS_BRANCH.apk + repo: xausky/UnityModManager \ No newline at end of file diff --git a/README.md b/README.md index 9acc527..a1a7e50 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Unity模组管理器 -> ⼀个便捷的程序可以修改游戏内资源包括:Unity游戏资源,Wwise音频资源 +> 一个便捷的程序可以修改游戏内资源包括:Unity游戏资源,Wwise音频资源 [![Crowdin](https://d322cqt584bo4o.cloudfront.net/unitymodmanager/localized.svg)](https://crowdin.com/project/unitymodmanager) [![Build Status](https://travis-ci.org/xausky/UnityModManager.svg?branch=master)](https://travis-ci.org/xausky/UnityModManager) diff --git a/app/build.gradle b/app/build.gradle index cdae0ea..97d94c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,27 +1,15 @@ -buildscript { - repositories { - maven { url 'https://maven.fabric.io/public' } - } - - dependencies { - classpath 'io.fabric.tools:gradle:1.27.0' - } -} apply plugin: 'com.android.application' apply plugin: 'io.fabric' - -repositories { - maven { url 'https://maven.fabric.io/public' } -} +apply plugin: 'com.google.firebase.firebase-perf' android { compileSdkVersion 28 defaultConfig { - applicationId "io.github.xausky.unitymodmanager" + applicationId "cn.xausky.umm" minSdkVersion 21 targetSdkVersion 23 - versionCode 300 - versionName "3.0.0" + versionCode 411 + versionName "4.1.1" ndk{ abiFilters "armeabi-v7a","x86" } @@ -33,7 +21,7 @@ android { } signingConfigs { releaseConfig { - storeFile file("../../xausky.jks") + storeFile file("../xausky.jks") storePassword project.hasProperty("KEYSTORE_PASS") ? KEYSTORE_PASS : System.getenv("KEYSTORE_PASS") keyAlias project.hasProperty("ALIAS_NAME") ? ALIAS_NAME : System.getenv("ALIAS_NAME") keyPassword project.hasProperty("ALIAS_PASS") ? ALIAS_PASS : System.getenv("ALIAS_PASS") @@ -44,7 +32,9 @@ android { signingConfig signingConfigs.releaseConfig } debug { + debuggable true jniDebuggable true + signingConfig signingConfigs.releaseConfig } } lintOptions { @@ -58,25 +48,27 @@ android { dependencies { implementation 'commons-io:commons-io:2.4' //最新版2.6使用新的JavaFileAPI,无法在目前Android版本上使用。 - implementation 'com.android.support:design:28.0.0' - implementation 'com.android.support:cardview-v7:28.0.0' - implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'com.hzy:libp7zip:1.6.0' //https://github.com/hzy3774/AndroidP7zip implementation 'com.github.topjohnwu:libsu:2.0.2' //https://github.com/topjohnwu/libsu - implementation('com.daimajia.slider:library:1.1.5') { - //https://github.com/daimajia/AndroidImageSlider - exclude group: 'com.android.support', module: 'support-v4' - } + implementation('com.daimajia.slider:library:1.1.5') + //https://github.com/daimajia/AndroidImageSlider implementation 'com.github.medyo:android-about-page:1.2.5' //https://github.com/medyo/android-about-page - implementation 'com.github.xausky:VirtualXposed:d5e7545365' + implementation 'com.github.xausky:VirtualXposed:12332ab93b' //https://github.com/xausky/VirtualXposed implementation 'com.github.bartwell:ExFilePicker:0c5a7c83ae' //https://github.com/bartwell/ExFilePicker implementation 'com.github.xausky:CheckVersionLib:ac25f0874e' //https://github.com/xausky/CheckVersionLib - implementation 'com.crashlytics.sdk.android:answers:1.4.7' - implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9' + implementation 'com.google.firebase:firebase-core:17.0.1' + implementation 'com.google.firebase:firebase-perf:18.0.1' + implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' + implementation 'com.google.android.gms:play-services-ads:18.1.1' } + +apply plugin: 'com.google.gms.google-services' diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..2e4b21f --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,69 @@ +{ + "project_info": { + "project_number": "999756837706", + "firebase_url": "https://unity-mod-manager.firebaseio.com", + "project_id": "unity-mod-manager", + "storage_bucket": "unity-mod-manager.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:999756837706:android:d0c619615d8f02fe4587b3", + "android_client_info": { + "package_name": "cn.xausky.umm" + } + }, + "oauth_client": [ + { + "client_id": "999756837706-t3gfo4q8adrfknhqm52gmbu7jbnneb3h.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDL7ySG-vDz4_iXaDcRC6SaeJk6rdREucc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "999756837706-t3gfo4q8adrfknhqm52gmbu7jbnneb3h.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:999756837706:android:21dd3da8337e5843", + "android_client_info": { + "package_name": "io.github.xausky.unitymodmanager" + } + }, + "oauth_client": [ + { + "client_id": "999756837706-t3gfo4q8adrfknhqm52gmbu7jbnneb3h.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyDL7ySG-vDz4_iXaDcRC6SaeJk6rdREucc" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "999756837706-t3gfo4q8adrfknhqm52gmbu7jbnneb3h.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1165bc1..049d436 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ @@ -8,6 +9,8 @@ + android:name="com.google.android.gms.ads.APPLICATION_ID" + android:value="ca-app-pub-5364789594685674~8707472956"/> diff --git a/app/src/main/cpp/libuabe/BundleFile.cc b/app/src/main/cpp/libuabe/BundleFile.cc index a2a8c11..33463a5 100644 --- a/app/src/main/cpp/libuabe/BundleFile.cc +++ b/app/src/main/cpp/libuabe/BundleFile.cc @@ -79,10 +79,11 @@ namespace xausky { BinaryStream* fileStream = new BinaryStream(data, size, true); delete[] data; MemoryFile* file = new MemoryFile(name, fileStream); + file->flag = flag; files.push_back(file); } } - void BundleFile::save(BinaryStream& bundleStream, int32_t maxBlockSize, int32_t bundleFlag, int16_t blocksFlag, int32_t fileFlag){ + void BundleFile::save(BinaryStream& bundleStream, int32_t maxBlockSize, int32_t bundleFlag, int16_t blocksFlag){ char uncompressedData[maxBlockSize], compressedData[maxBlockSize + 1024]; bundleStream.WriteStringToNull(fileType); bundleStream.WriteInt32(fileVersion); @@ -90,43 +91,39 @@ namespace xausky { bundleStream.WriteStringToNull(versionEngine); BinaryStream blocksStream(true); BinaryStream assertStream(true); + BinaryStream tempAssertStream(true); blocksStream.WriteConst(0, 0x10); - int sizeCount = 0; for(std::list::iterator it = files.begin(); it != files.end(); it++){ - sizeCount+=(*it)->stream->size(); + MemoryFile* file = (*it); + file->offset = tempAssertStream.positionOutput(); + (*it)->stream->WriteTo(tempAssertStream); + file->size = tempAssertStream.positionOutput() - file->offset; } - int blockCount = (sizeCount - 1)/maxBlockSize + 1; + int blockCount = (tempAssertStream.positionOutput() - 1)/maxBlockSize + 1; blocksStream.WriteInt32(blockCount); int uncompressedSize = 0; int compressedSize = 0; - int position = 0; - for(std::list::iterator it = files.begin(); it != files.end(); it++){ - MemoryFile* file = (*it); - file->offset = position; - do{ - file->stream->ReadData(uncompressedData, maxBlockSize); - uncompressedSize = file->stream->count(); - if(uncompressedSize > 0){ - blocksStream.WriteInt32(uncompressedSize); - compressedSize = LZ4_compress_HC(uncompressedData, compressedData, uncompressedSize, maxBlockSize + 1024, LZ4HC_CLEVEL_DEFAULT); - if(compressedSize <= 0){ - DecompressDataException e; - throw e; - } - blocksStream.WriteInt32(compressedSize); - blocksStream.WriteInt16(blocksFlag); - assertStream.WriteData(compressedData, compressedSize); - position += uncompressedSize; + do{ + tempAssertStream.ReadData(uncompressedData, maxBlockSize); + uncompressedSize = tempAssertStream.count(); + if(uncompressedSize > 0){ + blocksStream.WriteInt32(uncompressedSize); + compressedSize = LZ4_compress_HC(uncompressedData, compressedData, uncompressedSize, maxBlockSize + 1024, LZ4HC_CLEVEL_DEFAULT); + if(compressedSize <= 0){ + DecompressDataException e; + throw e; } - }while(uncompressedSize > 0 && !file->stream->eof()); - file->size = position - file->offset; - } + blocksStream.WriteInt32(compressedSize); + blocksStream.WriteInt16(blocksFlag); + assertStream.WriteData(compressedData, compressedSize); + } + }while(uncompressedSize > 0 && !tempAssertStream.eof()); blocksStream.WriteInt32(files.size()); for(std::list::iterator it = files.begin(); it != files.end(); it++){ MemoryFile* file = (*it); blocksStream.WriteInt64(file->offset); blocksStream.WriteInt64(file->size); - blocksStream.WriteInt32(fileFlag); + blocksStream.WriteInt32(file->flag); blocksStream.WriteStringToNull(file->name); } uncompressedSize = blocksStream.size(); diff --git a/app/src/main/cpp/libuabe/BundleFile.hh b/app/src/main/cpp/libuabe/BundleFile.hh index a644c5f..047bce0 100644 --- a/app/src/main/cpp/libuabe/BundleFile.hh +++ b/app/src/main/cpp/libuabe/BundleFile.hh @@ -22,7 +22,7 @@ namespace xausky { }; struct DecompressDataException : std::exception { - const char *what() const noexcept { return "decompress data excption"; } + const char *what() const noexcept { return "Decompress data exception"; } }; class BundleFile { @@ -31,8 +31,7 @@ namespace xausky { void open(BinaryStream &stream); - void save(BinaryStream &stream, int32_t maxBlockSize = 131072, int32_t bundleFlag = 67, - int16_t blocksFlag = 3, int32_t fileFlag = 4); + void save(BinaryStream &stream, int32_t maxBlockSize = 131072, int32_t bundleFlag = 67, int16_t blocksFlag = 3); void patch(map *> &mods); diff --git a/app/src/main/cpp/libuabe/MemoryFile.hh b/app/src/main/cpp/libuabe/MemoryFile.hh index e2a353f..f19f1a4 100644 --- a/app/src/main/cpp/libuabe/MemoryFile.hh +++ b/app/src/main/cpp/libuabe/MemoryFile.hh @@ -9,6 +9,7 @@ namespace xausky { ~MemoryFile(); string name; BinaryStream* stream; + int32_t flag; int64_t offset; int64_t size; }; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/MainActivity.java b/app/src/main/java/io/github/xausky/unitymodmanager/MainActivity.java index c257e96..cbd5aae 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/MainActivity.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/MainActivity.java @@ -1,21 +1,29 @@ package io.github.xausky.unitymodmanager; +import android.app.Activity; import android.app.Fragment; import android.app.ProgressDialog; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.NavigationView; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.util.Log; +import androidx.annotation.NonNull; + +import com.google.android.gms.ads.MobileAds; +import com.google.android.material.navigation.NavigationView; + +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBar; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + import android.view.View; import android.view.Menu; import android.view.MenuItem; @@ -26,13 +34,13 @@ import java.io.File; -import io.github.xausky.unitymodmanager.adapter.VisibilityAdapter; import io.github.xausky.unitymodmanager.fragment.BaseFragment; import io.github.xausky.unitymodmanager.fragment.HomeFragment; import io.github.xausky.unitymodmanager.fragment.ModFragment; import io.github.xausky.unitymodmanager.utils.ModUtils; public class MainActivity extends AppCompatActivity { + private static final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"}; private DrawerLayout drawerLayout; private FloatingActionButton actionButton; private NavigationView navigationView; @@ -56,9 +64,30 @@ protected void onNewIntent(Intent intent) { } } + /** + * 检查是否已被授权危险权限 + * @param permissions + * @return + */ + public boolean checkDangerousPermissions(Activity ac, String[] permissions) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return true; + } + for (String permission : permissions) { + if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED || ActivityCompat.shouldShowRequestPermissionRationale(ac, permission)) { + return false; + } + } + return true; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (!checkDangerousPermissions(this, REQUIRED_PERMISSIONS) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ + this.requestPermissions(REQUIRED_PERMISSIONS, 0); + } + MobileAds.initialize(this, "ca-app-pub-5364789594685674~8707472956"); setContentView(R.layout.activity_main); SharedPreferences preferences = this.getSharedPreferences("default", MODE_PRIVATE); BaseFragment.initialize(this); @@ -148,7 +177,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } public void launch(){ - if(homeFragment.apkModifyModel != HomeFragment.APK_MODIFY_MODEL_NONE && (homeFragment.apkPath == null || homeFragment.baseApkPath == null || !new File(homeFragment.baseApkPath).exists())){ + if(homeFragment.apkModifyModel != HomeFragment.APK_MODIFY_MODEL_NONE && homeFragment.apkModifyModel != HomeFragment.APK_MODIFY_MODEL_HOOK && (homeFragment.apkPath == null || homeFragment.baseApkPath == null || !new File(homeFragment.baseApkPath).exists())){ Toast.makeText(this, R.string.install_source_not_found, Toast.LENGTH_LONG).show(); } else { if(homeFragment.apkModifyModel == HomeFragment.APK_MODIFY_MODEL_NONE && homeFragment.obbSupport){ diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/MainApplication.java b/app/src/main/java/io/github/xausky/unitymodmanager/MainApplication.java index 2d471bd..4b2dbb7 100755 --- a/app/src/main/java/io/github/xausky/unitymodmanager/MainApplication.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/MainApplication.java @@ -6,12 +6,10 @@ import android.content.SharedPreferences; import android.os.Build; -import com.crashlytics.android.Crashlytics; import com.lody.virtual.client.NativeEngine; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.stub.VASettings; -import io.fabric.sdk.android.Fabric; import io.github.xausky.unitymodmanager.fragment.HomeFragment; import io.github.xausky.unitymodmanager.fragment.SettingFragment; @@ -25,7 +23,7 @@ public class MainApplication extends Application { protected void attachBaseContext(Context base) { super.attachBaseContext(base); SharedPreferences settings = base.getSharedPreferences(SettingFragment.SETTINGS_PREFERENCE_NAME, Context.MODE_PRIVATE); - if(Integer.valueOf(settings.getString("apk_modify_model", "1")) == HomeFragment.APK_MODIFY_MODEL_VIRTUAL){ + if(Integer.valueOf(settings.getString("apk_modify_model", "0")) == HomeFragment.APK_MODIFY_MODEL_VIRTUAL){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { NativeEngine.disableJit(Build.VERSION.SDK_INT); } @@ -43,6 +41,5 @@ protected void attachBaseContext(Context base) { @Override public void onCreate() { super.onCreate(); - Fabric.with(this, new Crashlytics()); } } diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/ShortcutActivity.java b/app/src/main/java/io/github/xausky/unitymodmanager/ShortcutActivity.java index d00c47b..ae88103 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/ShortcutActivity.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/ShortcutActivity.java @@ -5,7 +5,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.widget.Toast; import com.lody.virtual.client.core.VirtualCore; @@ -33,7 +33,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onPostCreate(@Nullable Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); SharedPreferences preferences = getSharedPreferences(SettingFragment.SETTINGS_PREFERENCE_NAME, Context.MODE_PRIVATE); - int apkModifyModel = Integer.valueOf(preferences.getString("apk_modify_model", "1")); + int apkModifyModel = Integer.valueOf(preferences.getString("apk_modify_model", "0")); if(apkModifyModel != APK_MODIFY_MODEL_VIRTUAL){ Toast.makeText(this, R.string.no_virtual_model_shortcut, Toast.LENGTH_LONG).show(); finish(); diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/AttachesAdapter.java b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/AttachesAdapter.java index fbb9cc6..48395c3 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/AttachesAdapter.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/AttachesAdapter.java @@ -5,11 +5,11 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/ModsAdapter.java b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/ModsAdapter.java index a945cc3..44f6d7b 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/ModsAdapter.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/ModsAdapter.java @@ -6,13 +6,13 @@ import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.drawable.Drawable; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; -import android.util.JsonWriter; + +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; + import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -36,7 +36,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -52,9 +51,7 @@ import io.github.xausky.unitymodmanager.dialog.PasswordDialog; import io.github.xausky.unitymodmanager.domain.Mod; import io.github.xausky.unitymodmanager.utils.ModUtils; -import io.github.xausky.unitymodmanager.utils.NativeUtils; -import static io.github.xausky.unitymodmanager.utils.NativeUtils.PatchApk; import static io.github.xausky.unitymodmanager.utils.NativeUtils.RESULT_STATE_INTERNAL_ERROR; /** diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/VisibilityAdapter.java b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/VisibilityAdapter.java index 8812dcf..63975a2 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/adapter/VisibilityAdapter.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/adapter/VisibilityAdapter.java @@ -6,11 +6,11 @@ import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/dialog/ConfirmDialog.java b/app/src/main/java/io/github/xausky/unitymodmanager/dialog/ConfirmDialog.java index ceca433..63e051a 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/dialog/ConfirmDialog.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/dialog/ConfirmDialog.java @@ -1,8 +1,8 @@ package io.github.xausky.unitymodmanager.dialog; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import io.github.xausky.unitymodmanager.R; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/dialog/PasswordDialog.java b/app/src/main/java/io/github/xausky/unitymodmanager/dialog/PasswordDialog.java index 5c8b88e..9bd9fe9 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/dialog/PasswordDialog.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/dialog/PasswordDialog.java @@ -1,8 +1,8 @@ package io.github.xausky.unitymodmanager.dialog; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import android.view.View; import android.widget.EditText; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/domain/Mod.java b/app/src/main/java/io/github/xausky/unitymodmanager/domain/Mod.java index 62b8e71..1e9ff10 100755 --- a/app/src/main/java/io/github/xausky/unitymodmanager/domain/Mod.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/domain/Mod.java @@ -1,8 +1,7 @@ package io.github.xausky.unitymodmanager.domain; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; -import java.util.List; import java.util.Set; /** diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/AttachFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/AttachFragment.java index 2ec7760..7e130a6 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/AttachFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/AttachFragment.java @@ -4,8 +4,8 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/HomeFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/HomeFragment.java index 35fa9ac..a6b23c1 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/HomeFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/HomeFragment.java @@ -1,28 +1,23 @@ package io.github.xausky.unitymodmanager.fragment; import android.app.Activity; -import android.app.PendingIntent; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.ShortcutManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.net.sip.SipRegistrationListener; -import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v4.content.pm.ShortcutInfoCompat; -import android.support.v4.content.pm.ShortcutManagerCompat; -import android.support.v4.graphics.drawable.IconCompat; -import android.support.v7.widget.CardView; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; +import androidx.core.graphics.drawable.IconCompat; +import androidx.cardview.widget.CardView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -33,41 +28,32 @@ import com.allenliu.versionchecklib.v2.AllenVersionChecker; import com.allenliu.versionchecklib.v2.builder.UIData; import com.allenliu.versionchecklib.v2.callback.RequestVersionListener; +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdView; import com.lody.virtual.client.core.InstallStrategy; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.remote.InstallResult; import com.lody.virtual.remote.InstalledAppInfo; -import io.github.xausky.unitymodmanager.MainActivity; import io.github.xausky.unitymodmanager.dialog.ConfirmDialog; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; 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.io.InputStream; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; import java.util.HashSet; -import javax.net.ssl.HttpsURLConnection; - import io.github.xausky.unitymodmanager.MainApplication; import io.github.xausky.unitymodmanager.R; import io.github.xausky.unitymodmanager.ShortcutActivity; import io.github.xausky.unitymodmanager.dialog.ApplicationChooseDialog; import io.github.xausky.unitymodmanager.utils.ModUtils; import io.github.xausky.unitymodmanager.utils.NativeUtils; -import ru.bartwell.exfilepicker.utils.Utils; /** * Created by xausky on 18-3-3. @@ -80,6 +66,7 @@ public class HomeFragment extends BaseFragment implements View.OnClickListener, public static final int APK_MODIFY_MODEL_NONE = 0; public static final int APK_MODIFY_MODEL_VIRTUAL = 1; public static final int APK_MODIFY_MODEL_ROOT = 2; + public static final int APK_MODIFY_MODEL_HOOK = 3; public String packageName; public String apkPath; public String baseApkPath; @@ -92,6 +79,7 @@ public class HomeFragment extends BaseFragment implements View.OnClickListener, public boolean obbSupport; private ConfirmDialog confirmDialog; private View view; + private AdView mAdView; private TextView summary; private TextView clientState; private TextView currentVersion; @@ -112,7 +100,7 @@ public class HomeFragment extends BaseFragment implements View.OnClickListener, public BaseFragment setBase(Context base) { settings = base.getSharedPreferences(SettingFragment.SETTINGS_PREFERENCE_NAME, Context.MODE_PRIVATE); packageName = settings.getString(PACKAGE_PREFERENCE_KEY, null); - apkModifyModel = Integer.valueOf(settings.getString("apk_modify_model", "1")); + apkModifyModel = Integer.valueOf(settings.getString("apk_modify_model", "0")); persistentSupport = settings.getBoolean("persistent_support", true); obbSupport = settings.getBoolean("obb_support", false); return super.setBase(base); @@ -123,7 +111,7 @@ public BaseFragment setBase(Context base) { public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { context = inflater.getContext(); settings = context.getSharedPreferences(SettingFragment.SETTINGS_PREFERENCE_NAME, Context.MODE_PRIVATE); - apkModifyModel = Integer.valueOf(settings.getString("apk_modify_model", "1")); + apkModifyModel = Integer.valueOf(settings.getString("apk_modify_model", "0")); persistentSupport = settings.getBoolean("persistent_support", true); obbSupport = settings.getBoolean("obb_support", false); dialog = new ApplicationChooseDialog(context, this, ALL_APPLICATION_PACKAGE_REGEX, apkModifyModel == APK_MODIFY_MODEL_VIRTUAL, true); @@ -155,6 +143,9 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, e.printStackTrace(); } currentVersion.setText(String.format(getText(R.string.home_current_version).toString(), currentVersionString)); + mAdView = view.findViewById(R.id.adView); + AdRequest adRequest = new AdRequest.Builder().build(); + mAdView.loadAd(adRequest); checkVersion(); } clientUpdate(); @@ -324,7 +315,7 @@ public void ImportMapFile() { private void clientUpdate() { String versionName = null; int versionCode = 0; - if (apkModifyModel == APK_MODIFY_MODEL_ROOT || apkModifyModel == APK_MODIFY_MODEL_NONE) { + if (apkModifyModel == APK_MODIFY_MODEL_ROOT || apkModifyModel == APK_MODIFY_MODEL_NONE || apkModifyModel == APK_MODIFY_MODEL_HOOK) { try { versionName = context.getPackageManager().getPackageInfo(packageName, 0).versionName; versionCode = context.getPackageManager().getPackageInfo(packageName, 0).versionCode; @@ -424,7 +415,7 @@ public void run() { final String resultString; String result = getString(R.string.install_failed); int versionCode = 0; - if (apkModifyModel == APK_MODIFY_MODEL_ROOT || apkModifyModel == APK_MODIFY_MODEL_NONE) { + if (apkModifyModel == APK_MODIFY_MODEL_ROOT || apkModifyModel == APK_MODIFY_MODEL_NONE || apkModifyModel == APK_MODIFY_MODEL_HOOK) { try { String basePath = HomeFragment.this.context.getFilesDir().getAbsolutePath() + "/base.apk"; if (apkModifyModel == APK_MODIFY_MODEL_ROOT) { @@ -478,7 +469,7 @@ public void run() { if (modFragment.getEnableItemCount() > 0) { modFragment.setNeedPatch(true); } - if (modFragment.getItemCount() > 0 && !HomeFragment.this.getActivity().isFinishing()) { + if (modFragment.getItemCount() > 0 && !((Activity)confirmDialog.getContext()).isFinishing()) { confirmDialog.show(); } } diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/InfoFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/InfoFragment.java index eccbd88..1ee7923 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/InfoFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/InfoFragment.java @@ -1,14 +1,13 @@ package io.github.xausky.unitymodmanager.fragment; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import io.github.xausky.unitymodmanager.R; import mehdi.sakout.aboutpage.AboutPage; -import mehdi.sakout.aboutpage.Element; /** * Created by xausky on 18-3-3. diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/ModFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/ModFragment.java index ec1c2cd..13356d4 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/ModFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/ModFragment.java @@ -6,8 +6,8 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -24,11 +24,8 @@ import org.apache.commons.io.IOUtils; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; -import java.net.URLEncoder; import java.util.Collections; import java.util.List; import java.util.TreeSet; @@ -230,7 +227,13 @@ public void onExternalChange() { public void run() { Toast.makeText(context, R.string.checked_external_mod_changed, Toast.LENGTH_LONG).show(); HomeFragment fragment = (HomeFragment)BaseFragment.fragment(R.id.nav_home, ModFragment.this.getActivity().getApplication()); - VirtualCore.get().killApp(fragment.packageName, 0); + if (fragment.apkModifyModel == HomeFragment.APK_MODIFY_MODEL_VIRTUAL){ + VirtualCore.get().killApp(fragment.packageName, 0); + } else { + if(Shell.rootAccess()){ + Shell.su("am force-stop " + fragment.packageName).exec(); + } + } MainActivity activity = (MainActivity)context; needPatch = true; activity.launch(); @@ -238,18 +241,18 @@ public void run() { }); } - public int patch(String apkPath, String baseApkPath, String persistentPath, String obbPath, String baseObbPath, String backupPath, int apkModifyModel, boolean persistentSupport, boolean obbSupport){ + public int patch(String apkPath, String baseApkPath, String persistentPath, String obbPath, String baseObbPath, String backupPath, int apkModifyModel, boolean persistentSupport, boolean obbSupport){ if(apkModifyModel == HomeFragment.APK_MODIFY_MODEL_ROOT){ if(!Shell.rootAccess()){ return ModUtils.RESULT_STATE_ROOT_ERROR; } //暂时禁用SELinux,并且修改目标APK权限为666。 - Shell.Sync.su("setenforce 0", "chmod 666 " + apkPath); + Shell.su("setenforce 0", "chmod 666 " + apkPath).exec(); } try { Log.d(MainApplication.LOG_TAG, "patch: apkPath=" + apkPath + ", baseApkPath=" + baseApkPath + ", apkModifyModel=" + apkModifyModel); List mods = adapter.getMods(); - File fusionFile = new File(getBase().getCacheDir().getAbsolutePath() + "/fusion"); + File fusionFile = new File(getBase().getFilesDir().getAbsolutePath() + "/fusion"); try { FileUtils.deleteDirectory(fusionFile); } catch (IOException e) { @@ -297,7 +300,7 @@ public int patch(String apkPath, String baseApkPath, String persistentPath, Stri e.printStackTrace(); } } - if(apkModifyModel != HomeFragment.APK_MODIFY_MODEL_NONE){ + if(apkModifyModel == HomeFragment.APK_MODIFY_MODEL_VIRTUAL || apkModifyModel == HomeFragment.APK_MODIFY_MODEL_ROOT){ int result = NativeUtils.PatchApk(baseApkPath, apkPath, fusionFile.getAbsolutePath()); if(result != NativeUtils.RESULT_STATE_OK){ Log.d(MainApplication.LOG_TAG, "Patch APK File Failed: " + result + ",apkPath:" + apkPath + ",baseApkPath:" + baseApkPath); @@ -322,7 +325,7 @@ public void run() { }finally { if(apkModifyModel == HomeFragment.APK_MODIFY_MODEL_ROOT){ //修改目标APK权限回644,并且重新启用SELinux。 - Shell.Sync.su("chmod 644 " + apkPath, "setenforce 0"); + Shell.su("chmod 644 " + apkPath, "setenforce 0").exec(); } } } diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/SettingFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/SettingFragment.java index 1b7a4b3..a457f6b 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/SettingFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/SettingFragment.java @@ -1,6 +1,9 @@ package io.github.xausky.unitymodmanager.fragment; import android.app.ProgressDialog; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Build; @@ -9,8 +12,10 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; -import android.support.annotation.Nullable; +import android.util.Base64; import android.util.Log; +import androidx.annotation.Nullable; + import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -26,8 +31,10 @@ import java.io.IOException; import io.github.xausky.unitymodmanager.R; +import io.github.xausky.unitymodmanager.utils.BackupUtil; import io.github.xausky.unitymodmanager.utils.ModUtils; +import static android.content.Context.CONTEXT_IGNORE_SECURITY; import static io.github.xausky.unitymodmanager.utils.ModUtils.RESULT_STATE_INTERNAL_ERROR; /** @@ -58,7 +65,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { if(preference.getKey().equals("setting_export_apk")){ HomeFragment homeFragment = (HomeFragment) BaseFragment.fragment(R.id.nav_home, this.getActivity().getApplication()); - if(homeFragment.apkModifyModel == HomeFragment.APK_MODIFY_MODEL_NONE){ + if(homeFragment.apkModifyModel == HomeFragment.APK_MODIFY_MODEL_NONE || homeFragment.apkModifyModel == HomeFragment.APK_MODIFY_MODEL_HOOK){ Toast.makeText(this.getActivity(), R.string.none_modify_export, Toast.LENGTH_LONG).show(); return super.onPreferenceTreeClick(preferenceScreen, preference); } @@ -78,6 +85,41 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen } else { homeFragment.crateShortcut(VirtualCore.get().getInstalledAppInfo(homeFragment.packageName,0)); } + } else if(preference.getKey().equals("copy_login_info")){ + try { + HomeFragment homeFragment = (HomeFragment) BaseFragment.fragment(R.id.nav_home, this.getActivity().getApplication()); + if (homeFragment.packageName.startsWith("com.kurogame")){ + ClipboardManager cm = (ClipboardManager) this.getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + Context targetContext = this.getActivity().createPackageContext(homeFragment.packageName, CONTEXT_IGNORE_SECURITY); + ClipData mClipData = ClipData.newPlainText("XMMLogin", Base64.encodeToString(BackupUtil.backupKuroGame(targetContext), Base64.DEFAULT)); + cm.setPrimaryClip(mClipData); + Toast.makeText(this.getActivity(), R.string.copy_login_success, Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(this.getActivity(), R.string.copy_login_failed_unsupported, Toast.LENGTH_LONG).show(); + } + } catch (Exception e){ + Log.w("UMM","Copy Login Failed.", e); + Toast.makeText(this.getActivity(), R.string.copy_login_failed, Toast.LENGTH_LONG).show(); + } + } else if(preference.getKey().equals("import_login_info")){ + try{ + HomeFragment homeFragment = (HomeFragment) BaseFragment.fragment(R.id.nav_home, this.getActivity().getApplication()); + if (homeFragment.packageName.startsWith("com.kurogame")){ + ClipboardManager cm = (ClipboardManager) this.getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + if(cm.getPrimaryClip() != null){ + Context targetContext = this.getActivity().createPackageContext(homeFragment.packageName, CONTEXT_IGNORE_SECURITY); + BackupUtil.restoreKuroGame(targetContext, Base64.decode(cm.getPrimaryClip().getItemAt(0).getText().toString(), Base64.DEFAULT)); + Toast.makeText(this.getActivity(), R.string.import_login_success, Toast.LENGTH_LONG).show(); + } else { + Toast.makeText(this.getActivity(), R.string.import_login_failed_empty, Toast.LENGTH_LONG).show(); + } + } else { + Toast.makeText(this.getActivity(), R.string.import_login_failed_unsupported, Toast.LENGTH_LONG).show(); + } + } catch (Exception e){ + Log.w("UMM", "Import Login Failed.",e); + Toast.makeText(this.getActivity(), R.string.import_login_failed, Toast.LENGTH_LONG).show(); + } } return super.onPreferenceTreeClick(preferenceScreen, preference); } @@ -85,7 +127,7 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { if(s.equals("apk_modify_model")){ - if(Integer.valueOf(sharedPreferences.getString("apk_modify_model", "1")) == HomeFragment.APK_MODIFY_MODEL_VIRTUAL && !VirtualCore.get().isStartup()){ + if(Integer.valueOf(sharedPreferences.getString("apk_modify_model", "0")) == HomeFragment.APK_MODIFY_MODEL_VIRTUAL && !VirtualCore.get().isStartup()){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { NativeEngine.disableJit(Build.VERSION.SDK_INT); } diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/VisibilityFragment.java b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/VisibilityFragment.java index 0b16898..081eac1 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/fragment/VisibilityFragment.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/fragment/VisibilityFragment.java @@ -3,22 +3,17 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetDialog; -import android.support.v7.widget.RecyclerView; -import android.util.Log; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; -import com.lody.virtual.client.core.InstallStrategy; import com.lody.virtual.client.core.VirtualCore; -import com.lody.virtual.remote.InstallResult; -import io.github.xausky.unitymodmanager.MainApplication; import io.github.xausky.unitymodmanager.R; -import io.github.xausky.unitymodmanager.adapter.AttachesAdapter; import io.github.xausky.unitymodmanager.adapter.VisibilityAdapter; import io.github.xausky.unitymodmanager.dialog.ApplicationChooseDialog; diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/utils/BackupUtil.java b/app/src/main/java/io/github/xausky/unitymodmanager/utils/BackupUtil.java new file mode 100644 index 0000000..4ad89e8 --- /dev/null +++ b/app/src/main/java/io/github/xausky/unitymodmanager/utils/BackupUtil.java @@ -0,0 +1,91 @@ +package io.github.xausky.unitymodmanager.utils; + +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import com.topjohnwu.superuser.Shell; + +import org.json.JSONObject; + +import static android.content.Context.MODE_PRIVATE; + +public class BackupUtil { + + public static byte[] backupKuroGame(Context context) { + String accountsDatabaseFile = context.getDatabasePath("zz_sdk_db").getAbsolutePath(); + String deviceIdFile = context.getFilesDir().getAbsolutePath() + "/shared_prefs/devicesyn.xml"; + try { + unprotectFilesWithRoot(accountsDatabaseFile + "*", deviceIdFile); + JSONObject root = new JSONObject(); + StringBuilder builder = new StringBuilder(); + try (SQLiteDatabase db = SQLiteDatabase.openDatabase(accountsDatabaseFile, null, SQLiteDatabase.OPEN_READONLY); + Cursor cursor = db.rawQuery("SELECT user_id,login_id,login_name,password,auto_login,last_login_time,login_type,local_login_count,user_type FROM sdkuser;", null)) { + while (cursor.moveToNext()) { + for (int i = 0; i < cursor.getColumnCount(); i++) { + builder.append(cursor.getString(i)); + if (i + 1 < cursor.getColumnCount()) { + builder.append(','); + } + } + if (!cursor.isLast()) { + builder.append('\n'); + } + } + } + root.put("accounts", builder.toString()); + SharedPreferences sharedPreferences = context.getSharedPreferences("devicesyn", MODE_PRIVATE); + String deviceId = sharedPreferences.getString("device_id", null); + root.put("device_id", deviceId); + return root.toString().getBytes(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + protectFilesWithRoot(accountsDatabaseFile + "*", deviceIdFile); + } + } + + public static void restoreKuroGame(Context context, byte[] data) { + String accountsDatabaseFile = context.getDatabasePath("zz_sdk_db").getAbsolutePath(); + String deviceIdFile = context.getFilesDir().getAbsolutePath() + "/shared_prefs/devicesyn.xml"; + try { + unprotectFilesWithRoot(accountsDatabaseFile + "*", deviceIdFile); + JSONObject root = new JSONObject(new String(data)); + String accounts = root.getString("accounts"); + try (SQLiteDatabase db = SQLiteDatabase.openDatabase(accountsDatabaseFile, null, SQLiteDatabase.OPEN_READWRITE)) { + for (String account : accounts.split("\n")){ + db.execSQL("INSERT INTO sdkuser(user_id,login_id,login_name,password,auto_login,last_login_time,login_type,local_login_count,user_type) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", account.split(",")); + } + } + SharedPreferences sharedPreferences = context.getSharedPreferences("devicesyn", MODE_PRIVATE); + sharedPreferences.edit().putString("device_id", root.getString("device_id")).commit(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + protectFilesWithRoot(accountsDatabaseFile + "*", deviceIdFile); + } + } + + private static void unprotectFilesWithRoot(String ...files){ + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= files.length; i++){ + builder.append(files[i - 1]); + if (i < files.length){ + builder.append(" "); + } + } + Shell.su("setenforce 0", "chmod 666 " + builder.toString()).exec(); + } + + private static void protectFilesWithRoot(String ...files){ + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= files.length; i++){ + builder.append(files[i - 1]); + if (i < files.length){ + builder.append(" "); + } + } + Shell.su("setenforce 1", "chmod 600 " + builder.toString()).exec(); + } +} diff --git a/app/src/main/java/io/github/xausky/unitymodmanager/utils/FabBehavior.java b/app/src/main/java/io/github/xausky/unitymodmanager/utils/FabBehavior.java index cd6f08c..8263d15 100644 --- a/app/src/main/java/io/github/xausky/unitymodmanager/utils/FabBehavior.java +++ b/app/src/main/java/io/github/xausky/unitymodmanager/utils/FabBehavior.java @@ -2,17 +2,14 @@ import android.animation.Animator; import android.content.Context; -import android.support.design.widget.CoordinatorLayout; -import android.support.v4.view.ViewCompat; -import android.support.v4.view.animation.FastOutSlowInInterpolator; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.view.ViewCompat; +import androidx.interpolator.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.view.ViewPropertyAnimator; import android.view.animation.Interpolator; -import io.github.xausky.unitymodmanager.MainApplication; - public class FabBehavior extends CoordinatorLayout.Behavior { private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator(); diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 5ea142a..f50c8a1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,4 +1,4 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/attach_fragment.xml b/app/src/main/res/layout/attach_fragment.xml index 11e1c33..9aaca1b 100644 --- a/app/src/main/res/layout/attach_fragment.xml +++ b/app/src/main/res/layout/attach_fragment.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 7e3168e..c371520 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -10,7 +10,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> - @@ -40,9 +40,9 @@ android:layout_margin="8dp" android:text="@string/home_current_version" /> - + - - - + - + - @@ -90,7 +90,20 @@ android:layout_height="wrap_content" android:layout_margin="10dp" android:text="@android:string/unknownName" /> - + + + + + diff --git a/app/src/main/res/layout/mod_fragment.xml b/app/src/main/res/layout/mod_fragment.xml index 1ac9349..eeccc84 100644 --- a/app/src/main/res/layout/mod_fragment.xml +++ b/app/src/main/res/layout/mod_fragment.xml @@ -2,7 +2,7 @@ - diff --git a/app/src/main/res/layout/navigation_content.xml b/app/src/main/res/layout/navigation_content.xml index 89ca91b..54863d0 100644 --- a/app/src/main/res/layout/navigation_content.xml +++ b/app/src/main/res/layout/navigation_content.xml @@ -1,20 +1,20 @@ - - - - + - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/visibility_fragment.xml b/app/src/main/res/layout/visibility_fragment.xml index 5aea0af..4127f6f 100644 --- a/app/src/main/res/layout/visibility_fragment.xml +++ b/app/src/main/res/layout/visibility_fragment.xml @@ -2,7 +2,7 @@ - diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 471ff41..f0cc888 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -96,11 +96,13 @@ No Modify VirtualApp Model Root Privilege Model (Caution) + Hook Model 0 1 2 + 3 Android OBB resource file patch support Android OBB resource file patch support, such as \"Honkai Impact 3\" JP service, SEA service, global service. @@ -116,4 +118,15 @@ Feature not available in non-virtual mode OnlineMods Is the legacy mod of the original client detected deleted? + Copy Login Information + Copy login information to clipboard to import other devices. Root permission is required. + Import Login Information + Import the login information from the clipboard into the device. + Copying login information succeeded! + Copying login information failed, unsupported game! + Failed to copy login information, make sure Root permissions and game are logged in! + Failed to import login information, it seems that there is no login information in Clipboard! + Importing login information succeeded! + Failed to import login information, unsupported games! + Failed to import login information! diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index a62f119..6997555 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -51,8 +51,8 @@ 먼저 홈 화면에서 클라이언트를 설치해주시고, 설치된 게임 파일이 제거되지 않은지 확인해주십시오. 지원되지 않는 기능입니다. 모드 설치에 실패하였습니다 - The modification of the OBB file failed. Please confirm that the setting client has the corresponding obb file. It is recommended to close the obb support and try again. - Get the root permission fails, please contact the root device or switch to other apk modification modes. + OBB 파일의 수정 하지 못했습니다. 설정 클라이언트 해당 obb 파일에 있는지 확인 하십시오. Obb 지원을 닫고 다시 시도 하는 것이 좋습니다. + 루트 권한 실패 얻을, 하시기 바랍니다 연락 루트 장치 또는 다른 apk 수정 모드 전환. 애플리케이션이 내부 저장소 읽기 및 쓰기 권한을 가지고 있지 않습니다. 모바일 기기의 설정에서 권한 설정을 해주십시오. 이 권한 없이는 애플리케이션이 제대로 작동하지 않습니다. 외부 모드 모니터링 시작: %s 외부 모드 모니터링 정지: %s @@ -95,11 +95,13 @@ 변경 없음 가상어플 방식 루트 권한 방식 (주의) + Hook Model 0 1 2 + 3 안드로이드 OBB 리소스 파일 패치 지원 안드로이드 OBB 리소스 파일 패치 지원 기능. 붕괴3 일본서버, 동남아시아 서버, 혹은 글로벌 서버를 위한 기능입니다. @@ -114,5 +116,16 @@ Mod [%s] 감압 오류 모듈 파일 손상 되지 않은 확인 하십시오. 가상 모드에서 사용할 수 없는 기능 OnlineMods - Is the legacy mod of the original client detected deleted? + 원래 클라이언트 감지의 레거시 모드 삭제? + Copy Login Information + Copy login information to clipboard to import other devices. Root permission is required. + Import Login Information + Import the login information from the clipboard into the device. + Copying login information succeeded! + Copying login information failed, unsupported game! + Failed to copy login information, make sure Root permissions and game are logged in! + Failed to import login information, it seems that there is no login information in Clipboard! + Importing login information succeeded! + Failed to import login information, unsupported games! + Failed to import login information! diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 4b52bbe..6b7b684 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -1,5 +1,4 @@ - - + Менеджер модов Unity Запустить игру @@ -95,11 +94,13 @@ Без модификации VirtualApp Root права (осторожно) + Hook Model 0 1 2 + 3 Поддержка патча OBB файла Поддержка патча OBB файла для Honkai Impact 3 JP SEA и global серверов. @@ -115,4 +116,11 @@ Функция не доступна в режиме non виртуального Моды на сервере (китайском) Is the legacy mod of the original client detected deleted? + Copying login information succeeded! + Copying login information failed, unsupported game! + Failed to copy login information, make sure Root permissions and game are logged in! + Failed to import login information, it seems that there is no login information in Clipboard! + Importing login information succeeded! + Failed to import login information, unsupported games! + Failed to import login information! diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 18b639c..a0333a0 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -95,11 +95,13 @@ 不修改 虚拟环境模式 Root权限模式(慎用) + Hook模式 0 1 2 + 3 安卓OBB资源文件补丁支持 安卓OBB资源文件补丁支持,比如《崩坏3》的日服,东南亚服,全球服。 @@ -115,4 +117,15 @@ 非虚拟模式下功能不可用 在线模组 检测到的原客户端的旧模组是否删除? + 复制登录信息 + 复制登录信息到剪切板以便于导入其他设备,需要Root权限。 + 导入登录信息 + 将剪切板里的登录信息导入本设备。 + 复制登录信息成功! + 复制登录信息失败,不支持的游戏! + 复制登录信息失败,确保Root权限和游戏已经登录! + 导入登录信息失败,好像剪切板没有登录信息哦! + 导入登录信息成功! + 导入登录信息失败,不支持的游戏! + 导入登录信息失败! diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 6638a57..6c41ccd 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -95,11 +95,13 @@ 不修改 虛擬環境模式 Root權限模式(慎用) + Hook模式 0 1 2 + 3 安卓OBB資源文件補丁支持 安卓OBB資源文件補丁支持,比如《崩壞3》的日服,東南亞服,全球服。 @@ -115,4 +117,15 @@ 非虛擬模式下功能不可用 在線模組 檢測到的原客戶端的舊模組是否刪除? + 复制登录信息 + 复制登录信息到剪切板以便于导入其他设备,需要Root权限。 + 导入登录信息 + 将剪切板里的登录信息导入本设备。 + 复制登录信息成功! + 复制登录信息失败,不支持的游戏! + 复制登录信息失败,确保Root权限和游戏已经登录! + 导入登录信息失败,好像剪切板没有登录信息哦! + 导入登录信息成功! + 导入登录信息失败,不支持的游戏! + 导入登录信息失败! diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ef7e9f..14e1c2a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,8 +2,8 @@ Unity Mod Manager Launch Game Home - Mod - Attach + Modules + Add-on Settings System About @@ -17,103 +17,116 @@ Korean - Bebridge - Enable mod: %d\nInstalled mod: %d\nInstalled attach: %d\nVisible applications: %d\nApplications in VirtualApp: %d + Enabled modules: %d\nInstalled modules: %d\nInstalled add-on: %d\nVisible applications: %d\nApplications in VirtualApp: %d Latest Version: %s - Latest Version: ..... + Latest Version: ... Current Version: %s - Click Install Client - Client version:%s + Click to install client. + Client version: %s icon - Processing + Processing... Confirm Cancel Prompt - Are you sure you want to delete [%s] attach? - Are you sure you want to remove [%s] visibility? - Failed to delete attach. - Delete attach successfully. - Remove visibility successfully. + Delete [%s] add-on? + Remove [%s] visibility? + Failed to delete add-on! + Add-on has successfully installed. + App visibility deleted successfully. Unity - Visibility - Warning, module file deletion failed: %s! - Are you sure to delete the module: %s? - Failed to create the directory. Please confirm that the application has external storage read and write permissions. - Same name mod %s already exists, skip import. + App Visibility + WARNING! Failed to delete module file: %s! + Delete module: %s? + Failed to create directory! Please make sure the Storage permission has been granted in Settings. + Import failed! %s is already exists. Please wait - In operation - Please enter the decompression password + In progress... + Enter password %d - Click to generate the mapping file (external resources need to be downloaded first) - Map file record (click to regenerate): %d + Click to generate mapping file (external resources need to download first) + File mapping record (click to regenerate): %d Introduction:\n%s %s - Author:%s - Please go to the home page to install the client first, and make sure the installation source is not uninstalled or deleted. - Unsupported operation. - The installation module failed. Please clear the data again, or go to BiliBili for help. - The modification of the OBB file failed. Please confirm that the setting client has the corresponding obb file. It is recommended to close the obb support and try again. - Get the root permission fails, please contact the root device or switch to other apk modification modes. - The application does not have permission to read and write phone storage, please go to the phone rights management interface to give, otherwise it can not run. - External mod monitoring start: %s - External mod monitoring stop: %s - There is no information available for viewing within the mod. - Please enter the decompression password for module [%s], wrong password tried: %s - Please select the client + Author: %s + Navigate to home to install client first. Make sure the client installation source is not uninstalled or deleted. + Operation denied. + Failed to install module! Please clear the app data and try again, or go to bilibili to seek for help. + Failed to modify OBB file! Please make sure the installed client has corresponding OBB file, or toggle off OBB patch and try again. + Failed to grant root permission! Please make sure your device has been rooted, or switch to another APK resource modification mode and try again. + Failed to grant Phone permission! Please make sure the Phone permission has been granted in Settings. This app wouldn\'t run if Phone permission is not granted. + Start monitoring external module: %s + Stop monitoring external module: %s + No information can be viewed in this module. + Enter password [%s], wrong password tried count: %s + Select a client Select from file Skip - New version release:%s - Update log: %s \n\n If the update fails, you can go to github.com to find the latest download address and update it yourself. - installation failed - Successful installation - After the installation is successful, you can create shortcuts in the settings interface. + New version released: %s + Changelog: %s \n\n If failed to update, please go to https://github.com/xausky/UnityModManager/releases and manually download APK. + Installation failed! + Successfully installed! + Successfully installed! You can tap to create game shortcut in the Settings panel. [Mod Manager] - Failed to create backup directory - Please install the client and download hot update resources first. - The mapping file was generated successfully. - Please make sure there is at least one change source. - my email - my bilibili - my github - Improved translation - Please install the client first to generate the index. - External module directory import mode is not recommended for no mod developers. - An external module change was detected and the game was restarted. - Import mod - Export integration package success: [%s] - Failed to export the integration package. Please make sure that the program can read and write external storage. - APK resource modification model - Choose how to modify the resources in the APK. If you do not modify the mode, you do not modify the APK resource. You can continue to use persistent resource patches. + Failed to create backup directory! + Please install a client and download hotfix first. + File mapping is generated successfully. + Please make sure there have at least one modifiable source. + Email + Bilibili + Github + Improve translation + Please install a client first to generate the index. + External module directory import mode. NOT recommended for non-mod developers. + External module changes detected! game will restart. + Import modules + Successfulled export integration package: [%s] + Failed to export the integration package! Please make sure the Storage permission has been granted in Settings. + APK resource modification mode + Select how to modify the resources in the APK. If you select "No modification", APK resource wouldn\'t be modified, you can continue to use persistent resource patches. Persistent resource patch support - Unity\'s PersistentDataPath path provides resource patch support, such as \"Honkai Impact 3\" UC version. - Export Integration APK file + Provide Unity\'s PersistentDataPath path resource patch support, such as \"Honkai Impact 3\" UC version. + Export Integrated APK file Click to export the patched APK file to out.apk in the internal storage root directory. Create a game shortcut - Create a game shortcut to go directly from the desktop to the game in the virtual environment without first opening the manager. + You can open the game directly from desktop in the virtual environment without opening the manager. Unable to export integrated package No Modify APK mode - No VirtualApp Model cannot create shortcuts. Start using the original icon. + VirtualApp Model doesn\'t exist in manager, create shortcuts failed. You can directly open the app directly in app drawer. - No Modify + No Modification VirtualApp Model - Root Privilege Model (Caution) + Root Privilege Mode (Proceed with caution) + Hook Model 0 1 2 + 3 - Android OBB resource file patch support - Android OBB resource file patch support, such as \"Honkai Impact 3\" JP service, SEA service, global service. - Using Obb support without modifying the APK mode may cause the game to fail to start. + Android OBB patch resource file support + ONLY toggle on if your app supports OBB file patching, such as \"Honkai Impact 3\" JP server, SEA server and global server. + Using OBB support without changing APK mode may cause the game fail to start! 0 0 unknown - Conflict files: %s - Display mod file conflict information - Display mod file conflict information for module authors to debug. - The number of valid files in mod [%s] is zero. Please make sure the mapping is generated correctly. - Mod [%s] decompression error, please confirm that the module file is not damaged. - Feature not available in non-virtual mode - OnlineMods - Is the legacy mod of the original client detected deleted? + Conflicted files: %s + View conflicted module file information + View conflicted module file information, this can let module authors easy to debug. + Valid module files [%s] is zero. Please make sure file mapping is generated correctly. + Module [%s] unzip error, please make sure the module file doesn\'t corrupted. + This feature is not available for non-virtual mode. + Online Modules + Does the legacy module has been deleted in original cilent? + Copy Login Information + Copy login information to clipboard to import other devices. Root permission is required. + Import Login Information + Import the login information from the clipboard into the device. + Copying login information succeeded! + Copying login information failed, unsupported game! + Failed to copy login information, make sure Root permissions and game are logged in! + Failed to import login information, it seems that there is no login information in Clipboard! + Importing login information succeeded! + Failed to import login information, unsupported games! + Failed to import login information! diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 2092d3b..65c46fa 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -4,7 +4,7 @@ android:key="apk_modify_model" android:title="@string/apk_modify_model_title" android:summary="@string/apk_modify_model_summary" - android:defaultValue="1" + android:defaultValue="0" android:entries="@array/apk_modify_model" android:entryValues="@array/apk_modify_model_values"/> - + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 832f110..1195513 100644 --- a/build.gradle +++ b/build.gradle @@ -4,9 +4,13 @@ buildscript { repositories { google() jcenter() + maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'io.fabric.tools:gradle:1.31.0' + classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.google.gms:google-services:4.3.0' + classpath 'com.google.firebase:perf-plugin:1.3.0' } } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..5465fec --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +android.enableJetifier=true +android.useAndroidX=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 79a4c98..1d99f1d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat Mar 16 10:40:49 CST 2019 +#Sun Jun 09 15:07:53 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/xausky.jks b/xausky.jks new file mode 100644 index 0000000..b90492c Binary files /dev/null and b/xausky.jks differ