diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4372f04..8333da5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '16.2' + xcode-version: '26.3' - name: Checkout uses: actions/checkout@v3 with: @@ -63,13 +63,13 @@ jobs: scheme: ${{ steps.scheme.outputs.scheme }} filetype_parameter: ${{ steps.filetype_parameter.outputs.filetype_parameter }} file_to_build: ${{ steps.file_to_build.outputs.file_to_build }} - run: xcodebuild analyze -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -sdk iphoneos -arch arm64 -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcpretty && exit ${PIPESTATUS[0]} + run: xcodebuild analyze -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "generic/platform=iOS" -sdk iphoneos -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcpretty && exit ${PIPESTATUS[0]} - name: Archive env: scheme: ${{ steps.scheme.outputs.scheme }} filetype_parameter: ${{ steps.filetype_parameter.outputs.filetype_parameter }} file_to_build: ${{ steps.file_to_build.outputs.file_to_build }} - run: xcodebuild archive -archivePath "$archive_path" -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -sdk iphoneos -arch arm64 -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcpretty && exit ${PIPESTATUS[0]} + run: xcodebuild archive -archivePath "$archive_path" -scheme "$scheme" -destination "generic/platform=iOS" -"$filetype_parameter" "$file_to_build" -sdk iphoneos -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcpretty && exit ${PIPESTATUS[0]} - name: Tar Build Artifact run: tar -cvf "$archive_path.xcarchive.tar" "$archive_path.xcarchive" - name: Upload a Build Artifact @@ -118,6 +118,7 @@ jobs: with: name: ${{ env.scheme }}.ipa path: ${{ env.scheme }}.ipa + compression-level: 0 release__nightly: name: Nightly Release diff --git a/.gitignore b/.gitignore index e3b7c1b..31458d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -xcuserdata \ No newline at end of file +xcuserdata +.vscode \ No newline at end of file diff --git a/Entitlement.xcodeproj/project.pbxproj b/Entitlement.xcodeproj/project.pbxproj index 1deff36..08e8728 100644 --- a/Entitlement.xcodeproj/project.pbxproj +++ b/Entitlement.xcodeproj/project.pbxproj @@ -10,11 +10,16 @@ 17EE68B02D848EA100B77523 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 17EE68AF2D848EA100B77523 /* Starscream */; }; 17EE68B32D848EF000B77523 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 17EE68B22D848EF000B77523 /* KeychainAccess */; }; 4EE1A6092D954CE9007D655E /* StosSign in Frameworks */ = {isa = PBXBuildFile; productRef = 4EE1A6082D954CE9007D655E /* StosSign */; }; + EN_LPROJ_BUILD /* en.lproj in Resources */ = {isa = PBXBuildFile; fileRef = EN_LPROJ /* en.lproj */; }; + ZH_LPROJ_BUILD /* zh-Hans.lproj in Resources */ = {isa = PBXBuildFile; fileRef = ZH_LPROJ /* zh-Hans.lproj */; }; + /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 173496F02D847E82007994DB /* Entitlement.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Entitlement.app; sourceTree = BUILT_PRODUCTS_DIR; }; 17D124782D85856000796C1D /* OpenSSL.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:67RAULRX93:Marcin Krzyzanowski"; lastKnownFileType = wrapper.xcframework; name = OpenSSL.xcframework; path = OpenSSL/Frameworks/OpenSSL.xcframework; sourceTree = ""; }; + EN_LPROJ /* en.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder.localized; path = Entitlement/Resources/en.lproj; sourceTree = ""; }; + ZH_LPROJ /* zh-Hans.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder.localized; path = Entitlement/Resources/zh-Hans.lproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ @@ -58,6 +63,8 @@ 173496F22D847E82007994DB /* Entitlement */, 173497042D847F5A007994DB /* Frameworks */, 173496F12D847E82007994DB /* Products */, + EN_LPROJ /* en.lproj */, + ZH_LPROJ /* zh-Hans.lproj */, ); sourceTree = ""; }; @@ -125,6 +132,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + zh-Hans, Base, ); mainGroup = 173496E72D847E82007994DB; @@ -149,6 +157,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + EN_LPROJ_BUILD /* en.lproj in Resources */, + ZH_LPROJ_BUILD /* zh-Hans.lproj in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Entitlement/AnisetteDataHelper.swift b/Entitlement/AnisetteDataHelper.swift index c536248..fd37451 100644 --- a/Entitlement/AnisetteDataHelper.swift +++ b/Entitlement/AnisetteDataHelper.swift @@ -3,6 +3,7 @@ // AltStore // // Created by Riley Testut on 1/7/20. +// Translated by jlj1102 on 2026/2/30. // Copyright © 2020 Riley Testut. All rights reserved. // @@ -37,10 +38,10 @@ final class AnisetteDataHelper: WebSocketDelegate { if url == nil { - throw "No Anisette Server Found!" + throw (NSLocalizedString("noanisetteurl", comment: "")) } - self.printOut("Anisette URL: \(self.url!.absoluteString)") + self.printOut("\(NSLocalizedString("anisetteurl", comment: "")) \(self.url!.absoluteString)") let ans : AnisetteData if let identifier = Keychain.shared.identifier, @@ -67,7 +68,7 @@ final class AnisetteDataHelper: WebSocketDelegate self.printOut("Error message contains -45061 (not provisioned), resetting adi.pb and retrying") Keychain.shared.adiPb = nil return try await provision() - } else { throw message ?? "Unknown error" } + } else { throw message ?? NSLocalizedString("unkerr", comment: "") } } } @@ -114,21 +115,21 @@ final class AnisetteDataHelper: WebSocketDelegate let jsonData = try JSONEncoder().encode(formattedJSON) let anisette = try JSONDecoder().decode(AnisetteData.self, from: jsonData) - self.printOut("Anisette is valid!") + self.printOut("\(NSLocalizedString("validanisetteurl", comment: ""))") return anisette } catch { - self.printOut("Anisette is invalid!!!!") + self.printOut("\(NSLocalizedString("invalidanisetteurl", comment: ""))") if v3 { - throw "Invalid anisette (the returned data may not have all the required fields)" + throw NSLocalizedString("invalidanisettefields", comment: "") } else { - throw "Invalid anisette (the returned data may not have all the required fields)" + throw NSLocalizedString("invalidanisettefields", comment: "") } } } else { if v3 { - throw "Invalid anisette (the returned data may not be in JSON)" + throw NSLocalizedString("invalidanisettejson", comment: "") } else { - throw "Invalid anisette (the returned data may not be in JSON)" + throw NSLocalizedString("invalidanisettejson", comment: "") } } } @@ -156,7 +157,7 @@ final class AnisetteDataHelper: WebSocketDelegate return try await self.startProvisioningSession() } else { self.printOut("Apple didn't give valid URLs! Got response: \(String(data: data, encoding: .utf8) ?? "not utf8")") - throw "Apple didn't give valid URLs. Please try again later" + throw NSLocalizedString("novalidurlsgiven", comment: "") } @@ -356,8 +357,8 @@ final class AnisetteDataHelper: WebSocketDelegate self.printOut("X-Mme-Device-Id: \(self.deviceId!)") return - } else { throw "v1 server is not supported" } - } else { throw "Couldn't fetch client info. The returned data may not be in JSON" } + } else { throw NSLocalizedString("invalidv1server", comment: "") } + } else { throw NSLocalizedString("invalidclientinfo", comment: "") } } } diff --git a/Entitlement/AppIDView.swift b/Entitlement/AppIDView.swift index 1c5c334..8755b4c 100644 --- a/Entitlement/AppIDView.swift +++ b/Entitlement/AppIDView.swift @@ -3,6 +3,7 @@ // Entitlement // // Created by s s on 2025/3/15. +// Modified by jlj1102 on 2026/2/19. // import SwiftUI @@ -18,7 +19,7 @@ struct AppIDEditView : View { Button { Task { await addIncreasedMemoryLimit() } } label: { - Text("Add Increased Memory Limit") + Text("addmemlimit") } } @@ -26,11 +27,11 @@ struct AppIDEditView : View { Text(viewModel.result) .font(.system(.subheadline, design: .monospaced)) } header: { - Text("Server Response") + Text("srvresp") } } - .alert("Error", isPresented: $errorShow){ - Button("OK".loc, action: { + .alert("err", isPresented: $errorShow){ + Button("ok".loc, action: { }) } message: { Text(errorInfo) @@ -69,17 +70,17 @@ struct AppIDView : View { } } } header: { - Text("App IDs") + Text("appids") } Section { - Button("Refresh") { + Button("refresh") { Task { await refreshButtonClicked() } } } } - .alert("Error", isPresented: $errorShow){ - Button("OK".loc, action: { + .alert("err", isPresented: $errorShow){ + Button("ok".loc, action: { }) } message: { Text(errorInfo) diff --git a/Entitlement/AppIDViewModel.swift b/Entitlement/AppIDViewModel.swift index c366d3e..cf987ec 100644 --- a/Entitlement/AppIDViewModel.swift +++ b/Entitlement/AppIDViewModel.swift @@ -27,7 +27,7 @@ class AppIDModel : ObservableObject, Hashable { func addIncreasedMemory() async throws { guard let team = DataManager.shared.model.team, let session = DataManager.shared.model.session else { - throw "Please Login First" + throw NSLocalizedString("loginfirst", comment: "") } let dateFormatter = ISO8601DateFormatter() @@ -71,7 +71,7 @@ class AppIDViewModel : ObservableObject { func fetchAppIDs() async throws { guard let team = DataManager.shared.model.team, let session = DataManager.shared.model.session else { - throw "Please Login First" + throw NSLocalizedString("loginfirst", comment: "") } let ids = try await withUnsafeThrowingContinuation { (c: UnsafeContinuation<[AppID], Error>) in @@ -80,7 +80,7 @@ class AppIDViewModel : ObservableObject { c.resume(throwing: error) } guard let appIDs else { - c.resume(throwing: "AppIDs is nil. Please try again or reopen the app.") + c.resume(throwing: NSLocalizedString("nulappid", comment: "")) return } c.resume(returning: appIDs) diff --git a/Entitlement/Assets.xcassets/AppIcon.appiconset/Contents.json b/Entitlement/Assets.xcassets/AppIcon.appiconset/Contents.json index 2305880..a601f00 100644 --- a/Entitlement/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Entitlement/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -3,7 +3,8 @@ { "idiom" : "universal", "platform" : "ios", - "size" : "1024x1024" + "size" : "1024x1024", + "filename" : "icon.png" }, { "appearances" : [ @@ -14,7 +15,8 @@ ], "idiom" : "universal", "platform" : "ios", - "size" : "1024x1024" + "size" : "1024x1024", + "filename" : "transicon.png" }, { "appearances" : [ @@ -25,7 +27,8 @@ ], "idiom" : "universal", "platform" : "ios", - "size" : "1024x1024" + "size" : "1024x1024", + "filename" : "transicon.png" } ], "info" : { diff --git a/Entitlement/Assets.xcassets/AppIcon.appiconset/icon-dark.png b/Entitlement/Assets.xcassets/AppIcon.appiconset/icon-dark.png new file mode 100644 index 0000000..749a8d5 Binary files /dev/null and b/Entitlement/Assets.xcassets/AppIcon.appiconset/icon-dark.png differ diff --git a/Entitlement/Assets.xcassets/AppIcon.appiconset/icon.png b/Entitlement/Assets.xcassets/AppIcon.appiconset/icon.png new file mode 100644 index 0000000..858c7a2 Binary files /dev/null and b/Entitlement/Assets.xcassets/AppIcon.appiconset/icon.png differ diff --git a/Entitlement/Assets.xcassets/AppIcon.appiconset/transicon.png b/Entitlement/Assets.xcassets/AppIcon.appiconset/transicon.png new file mode 100644 index 0000000..3bcac4f Binary files /dev/null and b/Entitlement/Assets.xcassets/AppIcon.appiconset/transicon.png differ diff --git a/Entitlement/ContentView.swift b/Entitlement/ContentView.swift index fcbfe2e..512d88c 100644 --- a/Entitlement/ContentView.swift +++ b/Entitlement/ContentView.swift @@ -12,11 +12,11 @@ struct ContentView: View { TabView { AppIDView(viewModel: AppIDViewModel()) .tabItem { - Label("App IDs".loc, systemImage: "square.stack.3d.up.fill") + Label("appids", systemImage: "square.stack.3d.up.fill") } SettingsView(viewModel: LoginViewModel()) .tabItem { - Label("Settings".loc, systemImage: "gearshape.fill") + Label("settings", systemImage: "gearshape.fill") } } diff --git a/Entitlement/LoginViewModel.swift b/Entitlement/LoginViewModel.swift index 9aa0e91..14e2c0b 100644 --- a/Entitlement/LoginViewModel.swift +++ b/Entitlement/LoginViewModel.swift @@ -69,11 +69,11 @@ class LoginViewModel: ObservableObject { if let account, let session { c.resume(returning: (account, session)) } else { - c.resume(throwing: "Account or session is nil. Please try again or reopen the app.") + c.resume(throwing: NSLocalizedString("nilaccountsession", comment: "")) } } } - logging(text: "Successfully signed in") + logging(text: NSLocalizedString("succeedlogin", comment: "")) DataManager.shared.model.account = account DataManager.shared.model.session = session @@ -81,7 +81,7 @@ class LoginViewModel: ObservableObject { Keychain.shared.appleIDPassword = self.password let team = try await fetchTeam(for: account, session: session) - logging(text: "Successfully fetched team") + logging(text: NSLocalizedString("succeedteamfetch", comment: "")) DataManager.shared.model.team = team Task{ await MainActor.run { @@ -104,7 +104,7 @@ class LoginViewModel: ObservableObject { } } guard let fetchedTeams, !fetchedTeams.isEmpty, let team = fetchedTeams.first else { - throw "Unable to Fetch Team!" + throw NSLocalizedString("failfetchteam", comment: "") } return team diff --git a/Entitlement/Resources/en.lproj/Localizable.strings b/Entitlement/Resources/en.lproj/Localizable.strings new file mode 100644 index 0000000..cedaf73 --- /dev/null +++ b/Entitlement/Resources/en.lproj/Localizable.strings @@ -0,0 +1,40 @@ +// From AppIDView.swift +appids = "App IDs"; +addmemlimit = "Add Increased Memory Limit"; +srvresp = "Server Response"; +err = "ERROR"; +ok = "OK"; +refresh = "Refresh"; +loginfirst = "Please Login first (OR your login status is bad)"; +// From AnisetteDataHelper.swift +noanisetteurl = "No Anisette Server is found. (https://ani.sidestore.io By Default)"; +novalidurlsgiven = "Apple didn't give valid URLs. Please try again later"; +anisetteurl = "Anisette URL:"; +nilappid = "AppIDs is nil. Please try again or reopen the app."; +unkerr = "Unknown Error"; +validanisetteurl = "Anisette URL valid!"; +nilaccountsession = "Account or session is nil. Please try again or reopen the app."; +succeedlogin = "Logged in successfully!"; +invalidanisetteurl = "Anisette URL is not valid!!!"; +invalidanisettejson = "Invalid anisette (the returned data may not be in JSON)"; +invalidanisettefields = "Invalid anisette (the returned data may not have all the required fields)"; +invalidv1server = "Invalid server"; +invalidclientinfo = "Couldn't fetch client info. The returned data may not be in JSON"; +// From SettingsView.swift & LoginViewModel.swift +settings = "Settings"; +email = "Email"; +teamid = "Team ID"; +login = "Login"; +account = "Account"; +aniserv = "Anisette Server"; +clrkey = "Clear Keychain"; +clrkeydesc = "If something went wrong during signing in, please try to clean up the keychain, repoen the app and try again."; +password = "Password"; +twofa = "Verification Code"; +continue = "Continue"; +debugging = "Debugging"; +cancel = "Cancel"; +succeedteamfetch = "Successfully fetched team"; +failfetchteam = "Unable to fetch team!"; +aniservdesc = "Default is ( https://ani.sidestore.io ), you may need to restart the app for it to take effect."; + diff --git a/Entitlement/Resources/zh-Hans.lproj/Localizable.strings b/Entitlement/Resources/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..910bad7 --- /dev/null +++ b/Entitlement/Resources/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,39 @@ +// From AppIDView.swift +appids = "应用ID"; +addmemlimit = "增加内存上限"; +srvresp = "服务器响应"; +err = "错误"; +ok = "确定"; +refresh = "刷新"; +loginfirst = "请你先登录喵~(如果已经登录就是出错了)"; +// From AnisetteDataHelper.swift +noanisetteurl = "找不到Anisette服务器喵,默认是(https://ani.sidestore.io)喵~"; +novalidurlsgiven = "苹果没有给出有效的URL喵~,请稍后再试喵~"; +anisetteurl = "Anisette服务器:"; +nilappid = "appid是空的喵~,重新启动软件喵~"; +unkerr = "未知错误"; +validanisetteurl = "Anisette服务器有效!"; +nilaccountsession = "账号无效喵~"; +succeedlogin = "登陆成功!恭喜!"; +invalidanisetteurl = "这个Anesette服务器不能用喵~"; +invalidanisettejson = "Anisette数据无效(返回的数据可能不是JSON格式)喵~"; +invalidanisettefields = "Anisette数据无效(返回的数据可能没有所有必要的字段)喵~"; +invalidv1server = "服务器无效"; +invalidclientinfo = "无法获取客户端信息(返回的数据可能不是JSON格式)喵~"; +// From SettingsView.swift & LoginViewModel.swift +settings = "设置"; +email = "邮箱"; +teamid = "团队ID"; +login = "登录"; +account = "账号"; +aniserv = "Anisette服务器"; +clrkey = "清理钥匙串"; +clrkeydesc = "如果登录时报错,请尝试清理钥匙串,再重新打开软件。"; +password = "密码"; +twofa = "二次验证码"; +continue = "继续"; +debugging = "调试日志"; +cancel = "取消"; +succeedteamfetch = "团队获取成功"; +failfetchteam = "无法获取团队!"; +aniservdesc = "默认是( https://ani.sidestore.io ),可能需要重启以生效"; \ No newline at end of file diff --git a/Entitlement/SettingsView.swift b/Entitlement/SettingsView.swift index ad14ca6..c889cac 100644 --- a/Entitlement/SettingsView.swift +++ b/Entitlement/SettingsView.swift @@ -3,7 +3,7 @@ // Entitlement // // Created by s s on 2025/3/14. -// +// Translated by jlj1102 on 2026/2/19. import SwiftUI import StosSign @@ -25,43 +25,45 @@ struct SettingsView: View { Section { if sharedModel.isLogin { HStack { - Text("Email") + Text("email") Spacer() Text(email) } HStack { - Text("Team ID") + Text("teamid") Spacer() Text(teamId) } } else { - Button("Sign in") { + Button("login") { viewModel.loginModalShow = true } } } header: { - Text("Account") + Text("account") } Section { HStack { - Text("Anisette Server URL") + Text("aniserv") Spacer() TextField("", text: $sharedModel.anisetteServerURL) .multilineTextAlignment(.trailing) } + } footer: { + Text("aniservdesc") } Section { - Button("Clean Up Keychain") { + Button("clrkey") { cleanUp() } } footer: { - Text("If something went wrong during signing in, please try to clean up the keychain, repoen the app and try again.") + Text("clrkeydesc") } } - .alert("Error", isPresented: $errorShow){ - Button("OK".loc, action: { + .alert("err", isPresented: $errorShow){ + Button("ok".loc, action: { }) } message: { Text(errorInfo) @@ -88,17 +90,17 @@ struct SettingsView: View { SecureField("", text: $viewModel.password) .disabled(viewModel.isLoginInProgress) } header: { - Text("Password") + Text("password") } if viewModel.needVerificationCode { Section { TextField("", text: $viewModel.verificationCode) } header: { - Text("Verification Code") + Text("twofa") } } Section { - Button("Continue") { + Button("continue") { Task{ await loginButtonClicked() } } } @@ -107,14 +109,14 @@ struct SettingsView: View { Text(viewModel.logs) .font(.system(.subheadline, design: .monospaced)) } header: { - Text("Debugging") + Text("debugging") } } - .navigationTitle("Sign in") + .navigationTitle("login") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarLeading) { - Button("Cancel", role: .cancel) { + Button("cancel", role: .cancel) { viewModel.loginModalShow = false } } diff --git a/README.md b/README.md index 1b962a6..5e199b9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ +
+ icon + + 中文 +
+ # Get More Ram A simple [StosSign](https://github.com/stossy11/StosSign) wrapper app that allows you to enable "Increased Memory Limit" for your sideloaded apps without using Xcode. +
The English and Chinese translation of this app is available! # How to use 1. Sideload this app @@ -7,10 +14,13 @@ A simple [StosSign](https://github.com/stossy11/StosSign) wrapper app that allow 3. Go to "App IDs" page 4. Tap Refresh 5. Tap the app you want to enable "Increased Memory Limit" -6. Tap "Add Increased Memory Limit" +6. "Tap "Add Increased Memory Limit" 7. Reinstall the app from SideStore/AltStore 8. Check if you have "Increased Memory Limit" +
Tip: Usually the app with "Increased Memory Limit" has a total memory above 4GB (about 6GB) +
You can check it out (especially sideloaded games) by enabling "Show Graphics HUD" in Developer in System Settings. # Credits -Stossy11 - For StosSign. -SideStore - Anisette Data fetching codes are stolen from SideStore +Stossy11 - For StosSign.
+SideStore - Anisette Data fetching codes are stolen from SideStore
+jlj1102 - This fork with icons and Chinese translation diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..3102017 --- /dev/null +++ b/README_CN.md @@ -0,0 +1,24 @@ +
+ icon + + English +
+ +# Get More Ram +
这是一个从[StosSign](https://github.com/stossy11/StosSign)分离出来的简单软件,它可以让你在没有Xcode的情况下给你的侧载软件增加内存上限。 + +# 如何使用 +1. 侧载这个软件 +2. 应用内打开设置,登录你用于签名要增加内存上限的软件的账户 +3. 打开"应用ID"页 +4. 点击刷新 +5. 点击那个你要增加内存上限的软件包名 +6. 点击"增加内存上限" +7. 重新在Sidestore或者Altsotre安装增加了内存上限的软件 +8. 检查你是否有更多的可使用内存 +
提示:一般而言,你的软件共用内存将会从4GB到6GB,你可以去系统设置开发者页打开图形HUD以进行内存监控 + +# 鸣谢 +Stossy11 - Stossign的制作者
+SideStore - 从SideStore借来获取数据的代码
+jlj1102 - 这个fork的中文以及图标