diff --git a/.bundle/config b/.bundle/config
deleted file mode 100644
index 44fc1dd..0000000
--- a/.bundle/config
+++ /dev/null
@@ -1,2 +0,0 @@
----
-BUNDLE_PATH: "Gems"
diff --git a/.gitignore b/.gitignore
index d7508f4..d2e0555 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,29 +1,3 @@
-### Windows ###
-# Windows thumbnail cache files
-Thumbs.db
-Thumbs.db:encryptable
-ehthumbs.db
-ehthumbs_vista.db
-
-# Dump file
-*.stackdump
-
-# Folder config file
-[Dd]esktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
-
-# Windows Installer files
-*.cab
-*.msi
-*.msix
-*.msm
-*.msp
-
-# Windows shortcuts
-*.lnk
-
### macOS ###
# General
.DS_Store
@@ -53,95 +27,35 @@ Network Trash Folder
Temporary Items
.apdisk
+### macOS Patch ###
+# iCloud generated files
+*.icloud
+
### Xcode ###
-# Xcode
-#
-# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
-
-## User settings
+# User settings
xcuserdata/
-## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
-*.xcscmblueprint
-*.xccheckout
-
-## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
-build/
-DerivedData/
-*.moved-aside
-*.pbxuser
-!default.pbxuser
-*.mode1v3
-!default.mode1v3
-*.mode2v3
-!default.mode2v3
-*.perspectivev3
-!default.perspectivev3
-
-## Gcc Patch
-/*.gcno
-
-## App packaging
-*.ipa
-*.dSYM.zip
-*.dSYM
-
### Xcode Patch ###
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
+!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
+/*.gcno
**/xcshareddata/WorkspaceSettings.xcsettings
-### Objective-C/Swift ###
+# Obj-C/Swift specific
*.hmap
-## Playgrounds
-timeline.xctimeline
-playground.xcworkspace
+# App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
-### CocoaPods ###
-## CocoaPods GitIgnore Template
+# Swift Package Manager
+.swiftpm/
+.build/
-# CocoaPods - Only use to conserve bandwidth / Save time on Pushing
-# - Also handy if you have a large number of dependant pods
-# - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
-Pods/
+### Workspace ###
-### Carthage ###
-# Carthage
-#
-# Add this line if you want to avoid checking in source code from Carthage dependencies.
-# Carthage/Checkouts
-
-Carthage/Build
-
-### fastlane ###
-# fastlane - A streamlined workflow tool for Cocoa deployment
-#
-# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
-# screenshots whenever they are needed.
-# For more information about the recommended setup visit:
-# https://docs.fastlane.tools/best-practices/source-control/#source-control
-
-# fastlane specific
-fastlane/report.xml
-
-# deliver temporary files
-fastlane/Preview.html
-
-# snapshot generated screenshots
-fastlane/screenshots/**/*.png
-fastlane/screenshots/screenshots.html
-
-# scan temporary files
-fastlane/test_output
-
-# Fastlane.swift runner binary
-fastlane/FastlaneRunner
-
-### Project ###
-
-Gems
-WeChatTweak.xcarchive
-WeChatTweak.framework
+/wechattweak
diff --git a/Gemfile b/Gemfile
deleted file mode 100644
index 3bf1d14..0000000
--- a/Gemfile
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-source 'https://rubygems.org'
-
-gem 'cocoapods'
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index cebb9c3..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,110 +0,0 @@
-GEM
- remote: https://rubygems.org/
- specs:
- CFPropertyList (3.0.7)
- base64
- nkf
- rexml
- activesupport (7.1.3.4)
- base64
- bigdecimal
- concurrent-ruby (~> 1.0, >= 1.0.2)
- connection_pool (>= 2.2.5)
- drb
- i18n (>= 1.6, < 2)
- minitest (>= 5.1)
- mutex_m
- tzinfo (~> 2.0)
- addressable (2.8.7)
- public_suffix (>= 2.0.2, < 7.0)
- algoliasearch (1.27.5)
- httpclient (~> 2.8, >= 2.8.3)
- json (>= 1.5.1)
- atomos (0.1.3)
- base64 (0.2.0)
- bigdecimal (3.1.8)
- claide (1.1.0)
- cocoapods (1.15.2)
- addressable (~> 2.8)
- claide (>= 1.0.2, < 2.0)
- cocoapods-core (= 1.15.2)
- cocoapods-deintegrate (>= 1.0.3, < 2.0)
- cocoapods-downloader (>= 2.1, < 3.0)
- cocoapods-plugins (>= 1.0.0, < 2.0)
- cocoapods-search (>= 1.0.0, < 2.0)
- cocoapods-trunk (>= 1.6.0, < 2.0)
- cocoapods-try (>= 1.1.0, < 2.0)
- colored2 (~> 3.1)
- escape (~> 0.0.4)
- fourflusher (>= 2.3.0, < 3.0)
- gh_inspector (~> 1.0)
- molinillo (~> 0.8.0)
- nap (~> 1.0)
- ruby-macho (>= 2.3.0, < 3.0)
- xcodeproj (>= 1.23.0, < 2.0)
- cocoapods-core (1.15.2)
- activesupport (>= 5.0, < 8)
- addressable (~> 2.8)
- algoliasearch (~> 1.0)
- concurrent-ruby (~> 1.1)
- fuzzy_match (~> 2.0.4)
- nap (~> 1.0)
- netrc (~> 0.11)
- public_suffix (~> 4.0)
- typhoeus (~> 1.0)
- cocoapods-deintegrate (1.0.5)
- cocoapods-downloader (2.1)
- cocoapods-plugins (1.0.0)
- nap
- cocoapods-search (1.0.1)
- cocoapods-trunk (1.6.0)
- nap (>= 0.8, < 2.0)
- netrc (~> 0.11)
- cocoapods-try (1.2.0)
- colored2 (3.1.2)
- concurrent-ruby (1.3.3)
- connection_pool (2.4.1)
- drb (2.2.1)
- escape (0.0.4)
- ethon (0.16.0)
- ffi (>= 1.15.0)
- ffi (1.17.0)
- fourflusher (2.3.1)
- fuzzy_match (2.0.4)
- gh_inspector (1.1.3)
- httpclient (2.8.3)
- i18n (1.14.5)
- concurrent-ruby (~> 1.0)
- json (2.7.2)
- minitest (5.24.1)
- molinillo (0.8.0)
- mutex_m (0.2.0)
- nanaimo (0.3.0)
- nap (1.1.0)
- netrc (0.11.0)
- nkf (0.2.0)
- public_suffix (4.0.7)
- rexml (3.2.9)
- strscan
- ruby-macho (2.5.1)
- strscan (3.1.0)
- typhoeus (1.4.1)
- ethon (>= 0.9.0)
- tzinfo (2.0.6)
- concurrent-ruby (~> 1.0)
- xcodeproj (1.24.0)
- CFPropertyList (>= 2.3.3, < 4.0)
- atomos (~> 0.1.3)
- claide (>= 1.0.2, < 2.0)
- colored2 (~> 3.1)
- nanaimo (~> 0.3.0)
- rexml (~> 3.2.4)
-
-PLATFORMS
- ruby
-
-DEPENDENCIES
- cocoapods
-
-BUNDLED WITH
- 2.4.19
diff --git a/LICENSE b/LICENSE
index f49a4e1..f36a7b7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,201 +1,662 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
- 1. Definitions.
+ Preamble
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
+ The precise terms and conditions for copying, distribution and
+modification follow.
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
+ TERMS AND CONDITIONS
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
+ 0. Definitions.
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
+ "This License" refers to version 3 of the GNU Affero General Public License.
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
+ 1. Source Code.
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
- END OF TERMS AND CONDITIONS
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
- APPENDIX: How to apply the Apache License to your work.
+ The Corresponding Source for a work in source code form is that
+same work.
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
+ 2. Basic Permissions.
- Copyright [yyyy] [name of copyright owner]
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
- http://www.apache.org/licenses/LICENSE-2.0
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
\ No newline at end of file
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+
+ Copyright (C) {{ year }} {{ organization }}
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/Makefile b/Makefile
index fcae79b..8f63ac1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,9 @@
-debug::
- xcodebuild build \
- -workspace WeChatTweak.xcworkspace \
- -scheme WeChatTweak \
- -configuration Debug
- DYLD_INSERT_LIBRARIES=WeChatTweak.framework/WeChatTweak /Applications/WeChat.app/Contents/MacOS/WeChat &
+.PHONY: build clean
-release::
- xcodebuild archive \
- -workspace WeChatTweak.xcworkspace \
- -scheme WeChatTweak \
- -destination 'generic/platform=macOS' \
- -archivePath WeChatTweak.xcarchive
+build::
+ swift build -c release --arch arm64 --arch x86_64
+ cp -f .build/apple/Products/Release/wechattweak ./wechattweak
clean::
- rm -rf WeChatTweak.xcarchive WeChatTweak.framework
-
-install::
- @echo "Makefile installation has been deprecated!!!"
- @echo "For more information: \033[33;32mhttps://github.com/sunnyyoung/WeChatTweak-CLI\033[0m."
-
-uninstall::
- @echo "Makefile installation has been deprecated!!!"
- @echo "For more information: \033[33;32mhttps://github.com/sunnyyoung/WeChatTweak-CLI\033[0m."
+ rm -rf .build
+ rm -f wechattweak
diff --git a/Package.resolved b/Package.resolved
new file mode 100644
index 0000000..906c3eb
--- /dev/null
+++ b/Package.resolved
@@ -0,0 +1,25 @@
+{
+ "object": {
+ "pins": [
+ {
+ "package": "PromiseKit",
+ "repositoryURL": "https://github.com/mxcl/PromiseKit",
+ "state": {
+ "branch": null,
+ "revision": "2bc44395edb4f8391902a9ff7c220471882a4d07",
+ "version": "8.2.0"
+ }
+ },
+ {
+ "package": "swift-argument-parser",
+ "repositoryURL": "https://github.com/apple/swift-argument-parser",
+ "state": {
+ "branch": null,
+ "revision": "cdd0ef3755280949551dc26dee5de9ddeda89f54",
+ "version": "1.6.2"
+ }
+ }
+ ]
+ },
+ "version": 1
+}
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..8b73cff
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,31 @@
+// swift-tools-version:6.0
+
+import PackageDescription
+
+let package = Package(
+ name: "WeChatTweak",
+ platforms: [
+ .macOS(.v12)
+ ],
+ products: [
+ .executable(
+ name: "wechattweak",
+ targets: [
+ "WeChatTweak"
+ ]
+ )
+ ],
+ dependencies: [
+ .package(url: "https://github.com/mxcl/PromiseKit", from: "8.0.0"),
+ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0")
+ ],
+ targets: [
+ .executableTarget(
+ name: "WeChatTweak",
+ dependencies: [
+ "PromiseKit",
+ .product(name: "ArgumentParser", package: "swift-argument-parser")
+ ]
+ )
+ ]
+)
diff --git a/Podfile b/Podfile
deleted file mode 100644
index 6963443..0000000
--- a/Podfile
+++ /dev/null
@@ -1,17 +0,0 @@
-platform :macos, '10.13'
-inhibit_all_warnings!
-
-target 'WeChatTweak' do
- pod 'JRSwizzle'
- pod 'GCDWebServer'
- pod 'fishhook', :podspec => 'fishhook.podspec'
-end
-
-post_install do |installer|
- installer.pods_project.targets.each do |target|
- target.build_configurations.each do |config|
- config.build_settings.delete 'ARCHS'
- config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET'
- end
- end
-end
diff --git a/Podfile.lock b/Podfile.lock
deleted file mode 100644
index 009698f..0000000
--- a/Podfile.lock
+++ /dev/null
@@ -1,29 +0,0 @@
-PODS:
- - fishhook (0.2)
- - GCDWebServer (3.5.4):
- - GCDWebServer/Core (= 3.5.4)
- - GCDWebServer/Core (3.5.4)
- - JRSwizzle (2.0.0)
-
-DEPENDENCIES:
- - fishhook (from `fishhook.podspec`)
- - GCDWebServer
- - JRSwizzle
-
-SPEC REPOS:
- trunk:
- - GCDWebServer
- - JRSwizzle
-
-EXTERNAL SOURCES:
- fishhook:
- :podspec: fishhook.podspec
-
-SPEC CHECKSUMS:
- fishhook: 415495c4be055473f437f0755286ae99e22d18da
- GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
- JRSwizzle: 7a6fdfe05231e2de26eb14835622d4c6c20c0b6c
-
-PODFILE CHECKSUM: 2882fbedfd770003d6828a279714d6ce0ef9a985
-
-COCOAPODS: 1.15.2
diff --git a/README-English.md b/README-English.md
deleted file mode 100644
index 0fc5c73..0000000
--- a/README-English.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# WeChatTweak-macOS
-
-[](LICENSE)
-[](README-English.md)
-[](README.md)
-[](https://t.me/wechattweak)
-
-A dynamic library tweak for WeChat macOS.
-
-
-
-## Features
-
-- Anti message revoked
- - Message list notification
- - System notification
- - Revoke message you sent
-- Multiple WeChat Instance
- - Launch from Dock menu
- - Run command: `open -n /Applications/WeChat.app`
-- Messages enhancement
- - Support stickers exporting
- - Support QRCode identifying
- - Support right-click copy link directly
- - Support opened by the system default browser directly
-- ~~Auto login without authentication~~ (Already supported by official)
-- UI Interface settings panel
-- Raycast extension support
-- Alfred workflow support
-- Launchbar action support
-
-## Usage
-
-Install command line tool [WeChatTweak-CLI](https://github.com/Sunnyyoung/WeChatTweak-CLI):
-
-```bash
-brew install sunnyyoung/repo/wechattweak-cli
-```
-
-Install/Upgrade/Uninstall Tweak:
-
-```bash
-sudo wechattweak-cli install # Install/Uninstall
-sudo wechattweak-cli uninstall # Uninstall
-```
-
-## References
-
-- [微信 macOS 客户端无限多开功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-wu-xian-duo-kai-gong-neng-shi-jian/)
-- [微信 macOS 客户端拦截撤回功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-lan-jie-che-hui-gong-neng-shi-jian/)
-- [让微信 macOS 客户端支持 Alfred](https://blog.sunnyyoung.net/rang-wei-xin-macos-ke-hu-duan-zhi-chi-alfred/)
-
-## Contributors
-
-This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
-
-[](https://github.com/Sunnyyoung/WeChatTweak-macOS/graphs/contributors)
-
-## License
-
-The [Apache License 2.0](LICENSE).
diff --git a/README.md b/README.md
index b178f97..d2e4224 100644
--- a/README.md
+++ b/README.md
@@ -1,73 +1,19 @@
-# WeChatTweak-macOS
+# WeChatTweak
[](LICENSE)
-[](README-English.md)
-[](README.md)
[](https://t.me/wechattweak)
-微信 macOS 客户端增强 Tweak 动态库。
-
-
-
## 功能
-- 阻止消息撤回
- - 消息列表通知
- - 系统通知
- - 正常撤回自己发出的消息
-- 客户端无限多开
- - 右键 Dock icon 登录新的微信账号
- - 命令行执行:`open -n /Applications/WeChat.app`
-- 消息处理增强
- - 支持任意表情导出
- - 支持二维码识别
- - 支持右键直接复制链接
- - 支持由系统默认浏览器直接打开
-- ~~重新打开应用无需手机认证~~(官方已经支持)
-- UI界面设置面板
-- 支持 Raycast extension
-- 支持 Alfred workflow
-- 支持 Launchbar action
+- [x] 阻止消息撤回
+- [ ] 客户端无限多开
## 使用
-**首次使用**安装 [WeChatTweak-CLI](https://github.com/Sunnyyoung/WeChatTweak-CLI):
-
```bash
-brew install sunnyyoung/repo/wechattweak-cli
+wechattweak patch
```
-安装/更新/卸载 Tweak:
-
-```bash
-sudo wechattweak-cli install # 安装/更新
-sudo wechattweak-cli uninstall # 卸载
-```
-
-## FAQ
-
-- 安装失败?
- 1. 请检查本地网络是否畅通。
- 2. 请检查是否安装了最新版本 WeChat 客户端,官网 & App Store 版本均可尝试。
- 3. 请检查 Terminal app 是否有正确的权限配置。
-- 功能失效?
- 请提交 **issue** 然后等待,或提交 **pull request** 一起发电。
-- Issue 没有响应 or 回复?
- 开源项目,用爱发电,耐心等。
-- 兼容旧版本客户端吗?
- 不,为了降低维护成本和保证更新速度,默认只支持**最新**版本客户端。
-- 会封号吗?
- 在**只使用该工具**的情况下**没有**出现过封号/风险提示,若有**使用过其他同类工具**则有可能会出现封号/风险提示,因此风险自负。
-- 安装出现 `codesign_allocate helper tool cannot be found or used` 错误?
- 该错误为系统问题,暂未清楚原因,一般情况下重新执行安装操作即可。
-- 安装完打开微信客户端提示 `没有权限打开应用程序`?
- 先卸载,再重新安装一次即可,如仍无法解决请重启电脑。实在搞不定的,到 [issues](https://github.com/sunnyyoung/WeChatTweak-macOS/issues) 里找找类似问题并尝试解决。
-- 截图失效?
- 系统偏好设置 -> 隐私 -> 删除微信并重新添加 -> 重启微信客户端。
-- 出现`“WeChat.app” cannot be opened because the developer cannot be verified.`怎么办?
- 进入 `WeChat.app` 所在目录,通过右键菜单打开。
-- 理性讨论。
-
## 参考
- [微信 macOS 客户端无限多开功能实践](https://blog.sunnyyoung.net/wei-xin-macos-ke-hu-duan-wu-xian-duo-kai-gong-neng-shi-jian/)
@@ -82,4 +28,4 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR
## License
-The [Apache License 2.0](LICENSE).
+The [AGPL-3.0](LICENSE).
diff --git a/Screenshot/overview.jpg b/Screenshot/overview.jpg
deleted file mode 100644
index 2818b0b..0000000
Binary files a/Screenshot/overview.jpg and /dev/null differ
diff --git a/Sources/WeChatTweak/Command.swift b/Sources/WeChatTweak/Command.swift
new file mode 100644
index 0000000..97493f7
--- /dev/null
+++ b/Sources/WeChatTweak/Command.swift
@@ -0,0 +1,60 @@
+//
+// Command.swift
+//
+// Created by Sunny Young.
+//
+
+import Foundation
+import PromiseKit
+import ArgumentParser
+
+struct Command {
+ enum Error: @unchecked Sendable, LocalizedError {
+ case executing(command: String, error: NSDictionary)
+
+ var errorDescription: String? {
+ switch self {
+ case let .executing(command, error):
+ return "Execute command: \(command) failed: \(error)"
+ }
+ }
+ }
+
+ static func patch(app: URL, config: Config) -> Promise {
+ print("------ Path ------")
+ return Promise { seal in
+ do {
+ seal.fulfill(try Patcher.patch(binary: app.appendingPathComponent("Contents/MacOS/WeChat"), config: config))
+ } catch {
+ seal.reject(error)
+ }
+ }
+ }
+
+ static func resign(app: URL) -> Promise {
+ print("------ Resign ------")
+ return firstly {
+ Command.execute(command: "codesign --remove-sign \(app.path)")
+ }.then {
+ Command.execute(command: "codesign --force --deep --sign - \(app.path)")
+ }.then {
+ Command.execute(command: "xattr -cr \(app.path)")
+ }
+ }
+
+ private static func execute(command: String) -> Promise {
+ return Promise { seal in
+ print("Execute command: \(command)")
+ var error: NSDictionary?
+ guard let script = NSAppleScript(source: "do shell script \"\(command)\"") else {
+ return seal.reject(Error.executing(command: command, error: ["error": "Create script failed."]))
+ }
+ script.executeAndReturnError(&error)
+ if let error = error {
+ seal.reject(Error.executing(command: command, error: error))
+ } else {
+ seal.fulfill(())
+ }
+ }
+ }
+}
diff --git a/Sources/WeChatTweak/Config.swift b/Sources/WeChatTweak/Config.swift
new file mode 100644
index 0000000..57ac6c4
--- /dev/null
+++ b/Sources/WeChatTweak/Config.swift
@@ -0,0 +1,110 @@
+//
+// Config.swift
+// WeChatTweak
+//
+// Created by Sunny Young on 2025/12/5.
+//
+
+import Foundation
+import MachO
+
+struct Config: Decodable {
+ enum Arch: String, Decodable {
+ case arm64
+ case x86_64
+
+ var cpu: UInt32 {
+ switch self {
+ case .arm64:
+ return UInt32(CPU_TYPE_ARM64)
+ case .x86_64:
+ return UInt32(CPU_TYPE_X86_64)
+ }
+ }
+ }
+
+ struct Entry: Decodable {
+ let arch: Arch
+ let addr: UInt64
+ let asm: Data
+
+ private enum CodingKeys: CodingKey {
+ case arch
+ case addr
+ case asm
+ }
+
+ init(from decoder: any Decoder) throws {
+ let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self)
+ self.arch = try container.decode(Arch.self, forKey: .arch)
+ self.addr = try {
+ let hex = try container.decode(String.self, forKey: .addr)
+ guard let value = UInt64(hex, radix: 16) else {
+ throw DecodingError.dataCorruptedError(
+ forKey: CodingKeys.addr,
+ in: container,
+ debugDescription: "Invalid Entry.addr"
+ )
+ }
+ return value
+ }()
+ self.asm = try {
+ let hex = try container.decode(String.self, forKey: .asm)
+ guard let value = Data(hex: hex) else {
+ throw DecodingError.dataCorruptedError(
+ forKey: CodingKeys.asm,
+ in: container,
+ debugDescription: "Invalid Entry.asm"
+ )
+ }
+ return value
+ }()
+ }
+ }
+
+ struct Target: Decodable {
+ let identifier: String
+ let entries: [Entry]
+
+ private enum CodingKeys: CodingKey {
+ case identifier
+ case entries
+ }
+
+ init(from decoder: any Decoder) throws {
+ let container = try decoder.container(keyedBy: CodingKeys.self)
+ self.identifier = try container.decode(String.self, forKey: .identifier)
+ self.entries = try container.decode([Entry].self, forKey: .entries)
+ }
+ }
+
+ let version: String
+ let targets: [Target]
+}
+
+private extension Data {
+ init?(hex: String) {
+ let chars = Array(hex.utf8)
+ guard chars.count % 2 == 0 else { return nil }
+
+ self.init()
+ self.reserveCapacity(chars.count / 2)
+
+ func nibble(_ c: UInt8) -> UInt8? {
+ switch c {
+ case 48...57: return c - 48 // '0'...'9'
+ case 65...70: return c - 55 // 'A'...'F'
+ case 97...102: return c - 87 // 'a'...'f'
+ default: return nil
+ }
+ }
+
+ var i = 0
+ while i < chars.count {
+ guard let hi = nibble(chars[i]),
+ let lo = nibble(chars[i + 1]) else { return nil }
+ append(hi << 4 | lo)
+ i += 2
+ }
+ }
+}
diff --git a/Sources/WeChatTweak/Patcher.swift b/Sources/WeChatTweak/Patcher.swift
new file mode 100644
index 0000000..142d339
--- /dev/null
+++ b/Sources/WeChatTweak/Patcher.swift
@@ -0,0 +1,161 @@
+//
+// Patcher.swift
+// WeChatTweak
+//
+// Created by Sunny Young on 2025/12/4.
+//
+
+import Darwin
+import MachO
+import Foundation
+
+struct Patcher {
+ enum Error: Swift.Error {
+ case invalidFile
+ case not64BitMachO(magic: UInt32)
+ case vaNotFound(arch: String, va: UInt64)
+ case noArchMatched
+ }
+
+ static func patch(binary: URL, config: Config) throws {
+ guard FileManager.default.fileExists(atPath: binary.path) else {
+ throw Error.invalidFile
+ }
+
+ let entries = config.targets.flatMap { $0.entries }
+ guard !entries.isEmpty else { throw Error.noArchMatched }
+
+ let fh = try FileHandle(forUpdating: binary)
+ defer { try? fh.close() }
+
+ // 读 magic 判断 fat / thin
+ guard let magicData = try fh.read(upToCount: 4), magicData.count == 4 else {
+ throw Error.invalidFile
+ }
+ let magicBE = magicData.withUnsafeBytes { $0.load(as: UInt32.self).bigEndian }
+ let isSwappedFat = (magicBE == FAT_CIGAM)
+
+ var patchedCount = 0
+ if magicBE == FAT_MAGIC || magicBE == FAT_CIGAM {
+ // FAT header: magic(4) + nfat_arch(4)
+ guard let nfatData = try fh.read(upToCount: 4), nfatData.count == 4 else {
+ throw Error.invalidFile
+ }
+ let rawNfat = nfatData.withUnsafeBytes { $0.load(as: UInt32.self) }
+ let nfat = isSwappedFat ? UInt32(littleEndian: rawNfat) : UInt32(bigEndian: rawNfat)
+
+ // 先读完 fat_arch 表,避免 patch 时移动文件指针影响后续读取
+ var archEntries: [(cputype: UInt32, offset: UInt32)] = []
+
+ for _ in 0..
-
-
-
- CFBundleIconFile
- icon.png
- CFBundleIdentifier
- com.viko16.LaunchBar.action.WeChatTweak
- CFBundleName
- WeChatTweak
- CFBundleVersion
- 1.0
- LBAbbreviation
- wc
- LBDescription
-
- LBAuthor
- viko16
- LBEmail
-
- LBSummary
- A LaunchBar action for WeChatTweak.
- LBTwitter
-
- LBWebsiteURL
- https://github.com/viko16
-
- LBScripts
-
- LBDefaultScript
-
- LBAcceptedArgumentTypes
-
- string
-
- LBKeepWindowActive
-
- LBLiveFeedbackEnabled
-
- LBRequiresArgument
-
- LBResultType
- unknown
- LBReturnsResult
-
- LBScriptName
- default.js
-
-
- LBTextInputTitle
- Search your friend...
-
-
diff --git a/WeChatTweak.lbaction/Contents/Resources/icon.png b/WeChatTweak.lbaction/Contents/Resources/icon.png
deleted file mode 100644
index 5e457bd..0000000
Binary files a/WeChatTweak.lbaction/Contents/Resources/icon.png and /dev/null differ
diff --git a/WeChatTweak.lbaction/Contents/Scripts/default.js b/WeChatTweak.lbaction/Contents/Scripts/default.js
deleted file mode 100644
index 07390e9..0000000
--- a/WeChatTweak.lbaction/Contents/Scripts/default.js
+++ /dev/null
@@ -1,40 +0,0 @@
-// LaunchBar Action Script
-
-function run(string) {
- if (!string) return [];
-
- var url = 'http://localhost:48065/wechat/search?keyword=';
- var result = HTTP.getJSON(url + encodeURIComponent(string.trim()));
-
- if (result == undefined) {
- LaunchBar.alert('HTTP.getJSON() returned undefined');
- return [];
- }
-
- if (result.error != undefined) {
- LaunchBar.log('Error in HTTP request: ' + result.error);
- return [];
- }
-
- var arr=[];
- var jsonArr=result.data.items;
- jsonArr.forEach(function (i) {
- arr.push( {
- title: i.title,
- subtitle: i.subtitle,
- icon: i.icon.path,
- action: "open",
- actionArgument: i.arg
- })
- });
-
-
- // return JSON.stringify(result.data);
- return arr;
-
-}
-
-function open(id) {
- LaunchBar.hide()
- HTTP.get('http://localhost:48065/wechat/start?session=' + id);
-}
diff --git a/WeChatTweak.xcodeproj/project.pbxproj b/WeChatTweak.xcodeproj/project.pbxproj
deleted file mode 100644
index 2553a14..0000000
--- a/WeChatTweak.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,523 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 56;
- objects = {
-
-/* Begin PBXBuildFile section */
- 7D14E5A41F6447DB00D75132 /* Alfred.h in Headers */ = {isa = PBXBuildFile; fileRef = 7D14E5A21F6447DB00D75132 /* Alfred.h */; };
- 7D14E5A51F6447DB00D75132 /* Alfred.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D14E5A31F6447DB00D75132 /* Alfred.m */; };
- 7D2194CC264701950068F4CC /* AntiRevoke.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D2194CA264701950068F4CC /* AntiRevoke.m */; };
- 7D54A05C20E74D9400CB5306 /* TweakPreferencesController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D54A05E20E74D9400CB5306 /* TweakPreferencesController.xib */; };
- 7D54A06A20E74FE500CB5306 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D54A06C20E74FE500CB5306 /* Localizable.strings */; };
- 7D64150827A9469900A8A398 /* ContextMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D64150627A9469900A8A398 /* ContextMenu.m */; };
- 7D64150C27A94B9600A8A398 /* Directory.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D64150B27A94B9600A8A398 /* Directory.m */; };
- 7D64150E27A94BEA00A8A398 /* MultipleInstances.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D64150D27A94BEA00A8A398 /* MultipleInstances.m */; };
- 7D64151027A94DE200A8A398 /* PreferencesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D64150F27A94DE200A8A398 /* PreferencesWindow.m */; };
- 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842331F4058AB00D42D79 /* WeChatTweak.m */; };
- 7DF842521F4058C600D42D79 /* TweakPreferencesController.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8424F1F4058C600D42D79 /* TweakPreferencesController.h */; };
- 7DF842531F4058C600D42D79 /* TweakPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842501F4058C600D42D79 /* TweakPreferencesController.m */; };
- 7DF8425B1F4058DD00D42D79 /* NSBundle+WeChatTweak.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */; };
- 7DF8425C1F4058DD00D42D79 /* NSBundle+WeChatTweak.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */; };
- 7DF842601F40590500D42D79 /* WeChatTweakHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DF8425F1F40590500D42D79 /* WeChatTweakHeaders.h */; };
- 7DF842651F40594400D42D79 /* Prefs-Tweak.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 7DF842641F40594400D42D79 /* Prefs-Tweak.tiff */; };
- 8F57F4CE7792FAE70DE20B02 /* libPods-WeChatTweak.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 015D5D0AC81B469FA2FF78F2 /* libPods-WeChatTweak.a */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- 015D5D0AC81B469FA2FF78F2 /* libPods-WeChatTweak.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WeChatTweak.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 7D14E5A21F6447DB00D75132 /* Alfred.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Alfred.h; sourceTree = ""; };
- 7D14E5A31F6447DB00D75132 /* Alfred.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Alfred.m; sourceTree = ""; };
- 7D2194CA264701950068F4CC /* AntiRevoke.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AntiRevoke.m; sourceTree = ""; };
- 7D54A05F20E74E4600CB5306 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TweakPreferencesController.xib; sourceTree = ""; };
- 7D54A07020E74FFD00CB5306 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; };
- 7D54A07120E7535F00CB5306 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; };
- 7D54A07220E7536300CB5306 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; };
- 7D64150627A9469900A8A398 /* ContextMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContextMenu.m; sourceTree = ""; };
- 7D64150B27A94B9600A8A398 /* Directory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Directory.m; sourceTree = ""; };
- 7D64150D27A94BEA00A8A398 /* MultipleInstances.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultipleInstances.m; sourceTree = ""; };
- 7D64150F27A94DE200A8A398 /* PreferencesWindow.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindow.m; sourceTree = ""; };
- 7DAE1DD727E828960009C01E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TweakPreferencesController.strings; sourceTree = ""; };
- 7DAE1DD927E828A50009C01E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/TweakPreferencesController.strings"; sourceTree = ""; };
- 7DAE1DDB27E828B00009C01E /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/TweakPreferencesController.strings"; sourceTree = ""; };
- 7DF842271F40583F00D42D79 /* WeChatTweak.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WeChatTweak.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WeChatTweak.h; sourceTree = ""; };
- 7DF842331F4058AB00D42D79 /* WeChatTweak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WeChatTweak.m; sourceTree = ""; };
- 7DF8424F1F4058C600D42D79 /* TweakPreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TweakPreferencesController.h; sourceTree = ""; };
- 7DF842501F4058C600D42D79 /* TweakPreferencesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TweakPreferencesController.m; sourceTree = ""; };
- 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+WeChatTweak.h"; sourceTree = ""; };
- 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+WeChatTweak.m"; sourceTree = ""; };
- 7DF8425F1F40590500D42D79 /* WeChatTweakHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeChatTweakHeaders.h; sourceTree = ""; };
- 7DF842641F40594400D42D79 /* Prefs-Tweak.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "Prefs-Tweak.tiff"; sourceTree = ""; };
- BAF38C6487242E521519F1D6 /* Pods-WeChatTweak.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WeChatTweak.release.xcconfig"; path = "Target Support Files/Pods-WeChatTweak/Pods-WeChatTweak.release.xcconfig"; sourceTree = ""; };
- C7011C4A6B32C90FC15D183A /* Pods-WeChatTweak.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WeChatTweak.debug.xcconfig"; path = "Target Support Files/Pods-WeChatTweak/Pods-WeChatTweak.debug.xcconfig"; sourceTree = ""; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 7DF842231F40583F00D42D79 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 8F57F4CE7792FAE70DE20B02 /* libPods-WeChatTweak.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 40D8B49D8195C4EF553380D3 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 015D5D0AC81B469FA2FF78F2 /* libPods-WeChatTweak.a */,
- );
- name = Frameworks;
- sourceTree = "";
- };
- 43C5C16B78FD88F555215AC8 /* Pods */ = {
- isa = PBXGroup;
- children = (
- C7011C4A6B32C90FC15D183A /* Pods-WeChatTweak.debug.xcconfig */,
- BAF38C6487242E521519F1D6 /* Pods-WeChatTweak.release.xcconfig */,
- );
- path = Pods;
- sourceTree = "";
- };
- 7D5AAF3520DF4B9700860EEE /* Controller */ = {
- isa = PBXGroup;
- children = (
- 7DF8424F1F4058C600D42D79 /* TweakPreferencesController.h */,
- 7DF842501F4058C600D42D79 /* TweakPreferencesController.m */,
- 7D54A05E20E74D9400CB5306 /* TweakPreferencesController.xib */,
- );
- path = Controller;
- sourceTree = "";
- };
- 7D5AAF3620DF4BA400860EEE /* Category */ = {
- isa = PBXGroup;
- children = (
- 7DF842571F4058DD00D42D79 /* NSBundle+WeChatTweak.h */,
- 7DF842581F4058DD00D42D79 /* NSBundle+WeChatTweak.m */,
- );
- path = Category;
- sourceTree = "";
- };
- 7D5AAF3820DF4BC400860EEE /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 7DF8425F1F40590500D42D79 /* WeChatTweakHeaders.h */,
- 7D54A06C20E74FE500CB5306 /* Localizable.strings */,
- );
- path = "Supporting Files";
- sourceTree = "";
- };
- 7DF8421D1F40583F00D42D79 = {
- isa = PBXGroup;
- children = (
- 7DF842291F40583F00D42D79 /* WeChatTweak */,
- 7DF842281F40583F00D42D79 /* Products */,
- 43C5C16B78FD88F555215AC8 /* Pods */,
- 40D8B49D8195C4EF553380D3 /* Frameworks */,
- );
- sourceTree = "";
- };
- 7DF842281F40583F00D42D79 /* Products */ = {
- isa = PBXGroup;
- children = (
- 7DF842271F40583F00D42D79 /* WeChatTweak.framework */,
- );
- name = Products;
- sourceTree = "";
- };
- 7DF842291F40583F00D42D79 /* WeChatTweak */ = {
- isa = PBXGroup;
- children = (
- 7DF8422A1F40583F00D42D79 /* WeChatTweak.h */,
- 7DF842331F4058AB00D42D79 /* WeChatTweak.m */,
- 7D2194CA264701950068F4CC /* AntiRevoke.m */,
- 7D64150B27A94B9600A8A398 /* Directory.m */,
- 7D64150D27A94BEA00A8A398 /* MultipleInstances.m */,
- 7D64150F27A94DE200A8A398 /* PreferencesWindow.m */,
- 7D64150627A9469900A8A398 /* ContextMenu.m */,
- 7D14E5A21F6447DB00D75132 /* Alfred.h */,
- 7D14E5A31F6447DB00D75132 /* Alfred.m */,
- 7D5AAF3620DF4BA400860EEE /* Category */,
- 7D5AAF3520DF4B9700860EEE /* Controller */,
- 7DF842631F40594400D42D79 /* Resources */,
- 7D5AAF3820DF4BC400860EEE /* Supporting Files */,
- );
- path = WeChatTweak;
- sourceTree = "";
- };
- 7DF842631F40594400D42D79 /* Resources */ = {
- isa = PBXGroup;
- children = (
- 7DF842641F40594400D42D79 /* Prefs-Tweak.tiff */,
- );
- path = Resources;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
- 7DF842241F40583F00D42D79 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 7DF8422C1F40583F00D42D79 /* WeChatTweak.h in Headers */,
- 7DF8425B1F4058DD00D42D79 /* NSBundle+WeChatTweak.h in Headers */,
- 7D14E5A41F6447DB00D75132 /* Alfred.h in Headers */,
- 7DF842601F40590500D42D79 /* WeChatTweakHeaders.h in Headers */,
- 7DF842521F4058C600D42D79 /* TweakPreferencesController.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
- 7DF842261F40583F00D42D79 /* WeChatTweak */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 7DF8422F1F40583F00D42D79 /* Build configuration list for PBXNativeTarget "WeChatTweak" */;
- buildPhases = (
- 6B4980DF8819FCBBE96201D3 /* [CP] Check Pods Manifest.lock */,
- 7DF842221F40583F00D42D79 /* Sources */,
- 7DF842231F40583F00D42D79 /* Frameworks */,
- 7DF842241F40583F00D42D79 /* Headers */,
- 7DF842251F40583F00D42D79 /* Resources */,
- 7DE5D07F218319DF00ABCE56 /* Export Framework */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = WeChatTweak;
- productName = WeChatTweak;
- productReference = 7DF842271F40583F00D42D79 /* WeChatTweak.framework */;
- productType = "com.apple.product-type.framework";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 7DF8421E1F40583F00D42D79 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = YES;
- LastUpgradeCheck = 1540;
- TargetAttributes = {
- 7DF842261F40583F00D42D79 = {
- CreatedOnToolsVersion = 8.3.3;
- ProvisioningStyle = Automatic;
- };
- };
- };
- buildConfigurationList = 7DF842211F40583F00D42D79 /* Build configuration list for PBXProject "WeChatTweak" */;
- compatibilityVersion = "Xcode 14.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- "zh-Hans",
- "zh-Hant",
- );
- mainGroup = 7DF8421D1F40583F00D42D79;
- productRefGroup = 7DF842281F40583F00D42D79 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 7DF842261F40583F00D42D79 /* WeChatTweak */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 7DF842251F40583F00D42D79 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 7DF842651F40594400D42D79 /* Prefs-Tweak.tiff in Resources */,
- 7D54A06A20E74FE500CB5306 /* Localizable.strings in Resources */,
- 7D54A05C20E74D9400CB5306 /* TweakPreferencesController.xib in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 6B4980DF8819FCBBE96201D3 /* [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-WeChatTweak-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;
- };
- 7DE5D07F218319DF00ABCE56 /* Export Framework */ = {
- isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- );
- name = "Export Framework";
- outputFileListPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "FRAMEWORK=\"${TARGET_NAME}.framework\"\nln -sf \"${BUILT_PRODUCTS_DIR}/${FRAMEWORK}\" \"${SRCROOT}\"\n";
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 7DF842221F40583F00D42D79 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 7D14E5A51F6447DB00D75132 /* Alfred.m in Sources */,
- 7DF842531F4058C600D42D79 /* TweakPreferencesController.m in Sources */,
- 7D64150827A9469900A8A398 /* ContextMenu.m in Sources */,
- 7D2194CC264701950068F4CC /* AntiRevoke.m in Sources */,
- 7DF842341F4058AB00D42D79 /* WeChatTweak.m in Sources */,
- 7D64151027A94DE200A8A398 /* PreferencesWindow.m in Sources */,
- 7D64150E27A94BEA00A8A398 /* MultipleInstances.m in Sources */,
- 7DF8425C1F4058DD00D42D79 /* NSBundle+WeChatTweak.m in Sources */,
- 7D64150C27A94B9600A8A398 /* Directory.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXVariantGroup section */
- 7D54A05E20E74D9400CB5306 /* TweakPreferencesController.xib */ = {
- isa = PBXVariantGroup;
- children = (
- 7D54A05F20E74E4600CB5306 /* Base */,
- 7DAE1DD727E828960009C01E /* en */,
- 7DAE1DD927E828A50009C01E /* zh-Hans */,
- 7DAE1DDB27E828B00009C01E /* zh-Hant */,
- );
- name = TweakPreferencesController.xib;
- sourceTree = "";
- };
- 7D54A06C20E74FE500CB5306 /* Localizable.strings */ = {
- isa = PBXVariantGroup;
- children = (
- 7D54A07020E74FFD00CB5306 /* en */,
- 7D54A07120E7535F00CB5306 /* zh-Hans */,
- 7D54A07220E7536300CB5306 /* zh-Hant */,
- );
- name = Localizable.strings;
- sourceTree = "";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 7DF8422D1F40583F00D42D79 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "-";
- COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 25;
- DEAD_CODE_STRIPPING = YES;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.13;
- MARKETING_VERSION = 1.5.0;
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = macosx;
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Debug;
- };
- 7DF8422E1F40583F00D42D79 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "-";
- COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 25;
- DEAD_CODE_STRIPPING = YES;
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.13;
- MARKETING_VERSION = 1.5.0;
- MTL_ENABLE_DEBUG_INFO = NO;
- SDKROOT = macosx;
- VERSIONING_SYSTEM = "apple-generic";
- };
- name = Release;
- };
- 7DF842301F40583F00D42D79 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = C7011C4A6B32C90FC15D183A /* Pods-WeChatTweak.debug.xcconfig */;
- buildSettings = {
- CODE_SIGN_IDENTITY = "";
- COMBINE_HIDPI_IMAGES = YES;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 9;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_VERSION = A;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2017年 Sunny Young. All rights reserved.";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = app.tweaks.WeChatTweak;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Debug;
- };
- 7DF842311F40583F00D42D79 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = BAF38C6487242E521519F1D6 /* Pods-WeChatTweak.release.xcconfig */;
- buildSettings = {
- CODE_SIGN_IDENTITY = "";
- COMBINE_HIDPI_IMAGES = YES;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 9;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_VERSION = A;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2017年 Sunny Young. All rights reserved.";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = app.tweaks.WeChatTweak;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 7DF842211F40583F00D42D79 /* Build configuration list for PBXProject "WeChatTweak" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 7DF8422D1F40583F00D42D79 /* Debug */,
- 7DF8422E1F40583F00D42D79 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 7DF8422F1F40583F00D42D79 /* Build configuration list for PBXNativeTarget "WeChatTweak" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 7DF842301F40583F00D42D79 /* Debug */,
- 7DF842311F40583F00D42D79 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 7DF8421E1F40583F00D42D79 /* Project object */;
-}
diff --git a/WeChatTweak.xcodeproj/xcshareddata/xcschemes/WeChatTweak.xcscheme b/WeChatTweak.xcodeproj/xcshareddata/xcschemes/WeChatTweak.xcscheme
deleted file mode 100644
index ce06a4d..0000000
--- a/WeChatTweak.xcodeproj/xcshareddata/xcschemes/WeChatTweak.xcscheme
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/WeChatTweak.xcworkspace/contents.xcworkspacedata b/WeChatTweak.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 26e23d6..0000000
--- a/WeChatTweak.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
diff --git a/WeChatTweak.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/WeChatTweak.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d9810..0000000
--- a/WeChatTweak.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- IDEDidComputeMac32BitWarning
-
-
-
diff --git a/WeChatTweak/Alfred.h b/WeChatTweak/Alfred.h
deleted file mode 100644
index 0113850..0000000
--- a/WeChatTweak/Alfred.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// Alfred.h
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/9/10.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import
-#import
-#import
-
-@interface AlfredManager : NSObject
-
-+ (instancetype)sharedInstance;
-
-- (void)startListener;
-- (void)stopListener;
-
-@end
diff --git a/WeChatTweak/Alfred.m b/WeChatTweak/Alfred.m
deleted file mode 100644
index 131dbf9..0000000
--- a/WeChatTweak/Alfred.m
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Alfred.m
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/9/10.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "Alfred.h"
-#import "WeChatTweak.h"
-
-@interface AlfredManager()
-
-@property (nonatomic, strong, nullable) GCDWebServer *server;
-
-@end
-
-@implementation AlfredManager
-
-+ (void)load {
- [AlfredManager.sharedInstance startListener];
-}
-
-+ (instancetype)sharedInstance {
- static dispatch_once_t onceToken;
- static AlfredManager *shared;
- dispatch_once(&onceToken, ^{
- shared = [[AlfredManager alloc] init];
- });
- return shared;
-}
-
-- (void)startListener {
- if (self.server != nil) {
- return;
- }
- self.server = [[GCDWebServer alloc] init];
- // Search contacts
- [self.server addHandlerForMethod:@"GET" path:@"/wechat/search" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) {
- NSString *path = ({
- NSString *path = nil;
- if ([objc_getClass("PathUtility") respondsToSelector:@selector(GetCurUserDocumentPath)]) {
- path = [objc_getClass("PathUtility") GetCurUserDocumentPath];
- } else {
- path = nil;
- }
- path;
- });
- NSString *keyword = [request.query[@"keyword"] lowercaseString] ? : @"";
-
- NSArray *contacts = ({
- MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
- ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
- GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
- NSMutableArray *array = [NSMutableArray array];
- [array addObjectsFromArray:[contactStorage GetAllFriendContacts]];
- [array addObjectsFromArray:[groupStorage GetGroupContactList:2 ContactType:0]];
- array;
- });
- NSArray *> *items = ({
- NSMutableArray *> *items = NSMutableArray.array;
- for (WCContactData *contact in contacts) {
- NSString *avatar = [NSString stringWithFormat:@"%@/Avatar/%@.jpg", path, [contact.m_nsUsrName md5String]];
- BOOL isOfficialAccount = (contact.m_uiCertificationFlag >> 0x3 & 0x1) == 1;
- BOOL containsNickName = [contact.m_nsNickName.lowercaseString containsString:keyword];
- BOOL containsUsername = [contact.m_nsUsrName.lowercaseString containsString:keyword];
- BOOL containsAliasName = [contact.m_nsAliasName.lowercaseString containsString:keyword];
- BOOL containsRemark = [contact.m_nsRemark.lowercaseString containsString:keyword];
- BOOL containsNickNamePinyin = [contact.m_nsFullPY.lowercaseString containsString:keyword];
- BOOL containsRemarkPinyin = [contact.m_nsRemarkPYFull.lowercaseString containsString:keyword];
- BOOL matchRemarkShortPinyin = [contact.m_nsRemarkPYShort.lowercaseString isEqualToString:keyword];
- if (!isOfficialAccount && (containsNickName || containsUsername || containsAliasName || containsRemark || containsNickNamePinyin || containsRemarkPinyin || matchRemarkShortPinyin)) {
- [items addObject:@{
- @"icon": @{
- @"path": [NSFileManager.defaultManager fileExistsAtPath:avatar] ? avatar : NSNull.null
- },
- @"title": ({
- id value = nil;
- if (contact.m_nsRemark.length) {
- value = contact.m_nsRemark;
- } else if (contact.m_nsNickName.length) {
- value = contact.m_nsNickName;
- } else {
- value = NSNull.null;
- }
- value;
- }),
- @"subtitle": contact.m_nsNickName.length ? contact.m_nsNickName : NSNull.null,
- @"arg": contact.m_nsUsrName.length ? contact.m_nsUsrName : NSNull.null,
- @"valid": @(contact.m_nsUsrName.length > 0)
- }];
- }
- }
- items;
- });
- return [GCDWebServerDataResponse responseWithJSONObject:@{@"items": items}];
- }];
- // Start session
- [self.server addHandlerForMethod:@"GET" path:@"/wechat/start" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) {
- WCContactData *contact = ({
- NSString *session = request.query[@"session"];
- WCContactData *contact = nil;
- if (session != nil) {
- MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
- if ([session rangeOfString:@"@chatroom"].location == NSNotFound) {
- ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
- contact = [contactStorage GetContact:session];
- } else {
- GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
- contact = [groupStorage GetGroupContact:session];
- }
- }
- contact;
- });
- dispatch_async(dispatch_get_main_queue(), ^{
- [[objc_getClass("WeChat") sharedInstance] startANewChatWithContact:contact];
- [[objc_getClass("WeChat") sharedInstance] showMainWindow];
- [[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
- });
- return [GCDWebServerResponse responseWithStatusCode:200];
- }];
- [self.server startWithOptions:@{
- GCDWebServerOption_Port: @(48065),
- GCDWebServerOption_BindToLocalhost: @(YES)
- } error:nil];
-}
-
-- (void)stopListener {
- if (self.server == nil) {
- return;
- }
- [self.server stop];
- [self.server removeAllHandlers];
- self.server = nil;
-}
-
-@end
diff --git a/WeChatTweak/AntiRevoke.m b/WeChatTweak/AntiRevoke.m
deleted file mode 100644
index 35cb99f..0000000
--- a/WeChatTweak/AntiRevoke.m
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-// AntiRevoke.m
-// WeChatTweak
-//
-// Created by Sunny Young on 2021/5/9.
-// Copyright © 2021 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-#import "NSBundle+WeChatTweak.h"
-
-@implementation NSObject (AntiRevoke)
-
-static void __attribute__((constructor)) tweak(void) {
- [objc_getClass("FFProcessReqsvrZZ") jr_swizzleMethod:NSSelectorFromString(@"DelRevokedMsg:msgData:") withMethod:@selector(tweak_DelRevokedMsg:msgData:) error:nil];
- [objc_getClass("FFProcessReqsvrZZ") jr_swizzleMethod:NSSelectorFromString(@"notifyAddRevokePromptMsgOnMainThread:msgData:") withMethod:@selector(tweak_notifyAddRevokePromptMsgOnMainThread:msgData:) error:nil];
-
- [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"initWithFrame:") withMethod:@selector(tweak_initWithFrame:) error:nil];
- [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"populateWithMessage:") withMethod:@selector(tweak_populateWithMessage:) error:nil];
- [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"layout") withMethod:@selector(tweak_layout) error:nil];
-}
-
-- (void)tweak_DelRevokedMsg:(NSString *)session msgData:(MessageData *)messageData {
- if (messageData.isSendFromSelf) {
- [self tweak_DelRevokedMsg:session msgData:messageData];
- } else {
- messageData.mesSvrID = messageData.mesLocalID;
- [((FFProcessReqsvrZZ *)self) ModifyMsgData:session msgData:messageData];
- dispatch_async(dispatch_get_main_queue(), ^{
- [((FFProcessReqsvrZZ *)self) notifyDelMsgOnMainThread:session msgData:messageData isRevoke:YES];
- [((FFProcessReqsvrZZ *)self) notifyAddMsgOnMainThread:session msgData:messageData];
- });
- }
-}
-
-- (void)tweak_notifyAddRevokePromptMsgOnMainThread:(NSString *)session msgData:(MessageData *)messageData {
- MessageData *localMessage = [((FFProcessReqsvrZZ *)self) GetMsgData:session localId:messageData.mesLocalID];
- if (!localMessage || localMessage.mesSvrID != messageData.mesLocalID) {
- [self tweak_notifyAddRevokePromptMsgOnMainThread:session msgData:messageData];
- } else {
- MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
- NSUserNotification *userNotification = [[NSUserNotification alloc] init];
- BOOL isChatStatusNotifyOpen = YES;
- if ([session rangeOfString:@"@chatroom"].location == NSNotFound) {
- ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
- WCContactData *contact = [contactStorage GetContact:session];
- isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen];
- userNotification.informativeText = messageData.msgContent;
- } else {
- GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
- WCContactData *groupContact = [groupStorage GetGroupContact:session];
- isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen];
- NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.Group"];
- userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, messageData.msgContent];
- }
- // Dispatch notification
- dispatch_async(dispatch_get_main_queue(), ^{
- // Deliver notification
- WeChatTweakNotificationType notificationType = WeChatTweak.notificationType;
- if (notificationType == WeChatTweakNotificationTypeReceiveAll || (notificationType == WeChatTweakNotificationTypeInherited && isChatStatusNotifyOpen)) {
- [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
- }
- });
- }
-}
-
-- (instancetype)tweak_initWithFrame:(NSRect)arg1 {
- MMMessageCellView *view = (MMMessageCellView *)[self tweak_initWithFrame:arg1];
- NSTextField *revokeTextField = [[NSTextField alloc] init];
- revokeTextField.hidden = YES;
- revokeTextField.editable = NO;
- revokeTextField.selectable = NO;
- revokeTextField.bordered = NO;
- revokeTextField.drawsBackground = NO;
- revokeTextField.usesSingleLineMode = YES;
- revokeTextField.tag = 9527;
- revokeTextField.stringValue = [NSBundle.tweakBundle localizedStringForKey:@"Tweak.Message.RecalledMark"];
- revokeTextField.font = [NSFont systemFontOfSize:7.0];
- revokeTextField.textColor = [NSColor lightGrayColor];
- [revokeTextField sizeToFit];
- [view addSubview:revokeTextField];
- return view;
-}
-
-- (void)tweak_populateWithMessage:(MMMessageTableItem *)tableItem {
- [self tweak_populateWithMessage:tableItem];
- BOOL recalled = tableItem.message.mesSvrID && tableItem.message.mesSvrID == tableItem.message.mesLocalID;
- [((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) {
- if (view.tag != 9527) {
- return ;
- }
- *stop = YES;
- view.hidden = !recalled;
- }];
- ((MMMessageCellView *)self).layer.backgroundColor = recalled ? WeChatTweak.maskColor.CGColor : nil;
-}
-
-- (void)tweak_layout {
- [self tweak_layout];
- [((MMMessageCellView *)self).subviews enumerateObjectsUsingBlock:^(__kindof NSView * _Nonnull view, NSUInteger index, BOOL * _Nonnull stop) {
- if (view.tag != 9527) {
- return;
- }
- *stop = YES;
- view.frame = ({
- NSView *avatarView = ((MMMessageCellView *)self).avatarImgView;
- CGFloat x = CGRectGetMidX(avatarView.frame) - CGRectGetWidth(view.frame) / 2.0;
- CGFloat y = CGRectGetMinY(avatarView.frame) - CGRectGetHeight(view.frame);
- NSRect frame = NSMakeRect(x, y, CGRectGetWidth(view.frame), CGRectGetHeight(view.frame));
- frame;
- });
- }];
-}
-
-@end
diff --git a/WeChatTweak/Category/NSBundle+WeChatTweak.h b/WeChatTweak/Category/NSBundle+WeChatTweak.h
deleted file mode 100644
index 6995c53..0000000
--- a/WeChatTweak/Category/NSBundle+WeChatTweak.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// NSBundle+WeChatTweak.h
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/12.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import
-
-@interface NSBundle (WeChatTweak)
-
-+ (instancetype)tweakBundle;
-- (NSString *)localizedStringForKey:(NSString *)key;
-
-@end
diff --git a/WeChatTweak/Category/NSBundle+WeChatTweak.m b/WeChatTweak/Category/NSBundle+WeChatTweak.m
deleted file mode 100644
index 1f06bf6..0000000
--- a/WeChatTweak/Category/NSBundle+WeChatTweak.m
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// NSBundle+WeChatTweak.m
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/12.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "NSBundle+WeChatTweak.h"
-
-@implementation NSBundle (WeChatTweak)
-
-+ (instancetype)tweakBundle {
- return [NSBundle bundleWithIdentifier:@"app.tweaks.WeChatTweak"];
-}
-
-- (NSString *)localizedStringForKey:(NSString *)key {
- return [self localizedStringForKey:key value:nil table:nil];
-}
-
-@end
diff --git a/WeChatTweak/ContextMenu.m b/WeChatTweak/ContextMenu.m
deleted file mode 100644
index 673ec05..0000000
--- a/WeChatTweak/ContextMenu.m
+++ /dev/null
@@ -1,209 +0,0 @@
-//
-// ContextMenu.m
-// WeChatTweak
-//
-// Created by Sunny Young on 2022/2/1.
-// Copyright © 2022 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-#import "NSBundle+WeChatTweak.h"
-
-#import
-
-typedef NS_ENUM(NSUInteger, OpenMapMenuType) {
- OpenMapMenuTypeGoogleMaps = 0,
- OpenMapMenuTypeAmap
-};
-
-@implementation NSObject (ContextMenu)
-
-static void __attribute__((constructor)) tweak(void) {
- [objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"contextMenu") withMethod:@selector(tweak_contextMenu) error:nil];
-}
-
-- (id)tweak_contextMenu {
- NSMenu *menu = (NSMenu *)[self tweak_contextMenu];
- if ([self isKindOfClass:objc_getClass("MMMessageCellView")]) {
- switch (((MMMessageCellView *)self).messageTableItem.message.messageType) {
- case MessageDataTypeAppUrl: {
- ReaderWrap *wrap = ({
- ReaderWrap *wrap = nil;
- if ([self isKindOfClass:objc_getClass("MMAppSingleReaderMessageCellView")]) {
- MMAppSingleReaderMessageCellView *cell = (MMAppSingleReaderMessageCellView *)self;
- wrap = cell.readerData;
- } else if ([self isKindOfClass:objc_getClass("MMAppMultipleReaderMessageCellView")]) {
- MMAppMultipleReaderMessageCellView *cell = (MMAppMultipleReaderMessageCellView *)self;
- wrap = (cell.selectedReaderWrapIndex < cell.readerMessages.count) ? cell.readerMessages[cell.selectedReaderWrapIndex] : nil;
- } else {
- wrap = nil;
- }
- wrap;
- });
- if (wrap) {
- [menu addItem:NSMenuItem.separatorItem];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.CopyLink"]
- action:@selector(tweakCopyLink:)
- keyEquivalent:@"c"];
- item.target = wrap;
- item;
- })];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInBrowser"]
- action:@selector(tweakOpenLink:)
- keyEquivalent:@"o"];
- item.target = wrap;
- item;
- })];
- }
- break;
- }
- case MessageDataTypeImage: {
- [menu addItem:NSMenuItem.separatorItem];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.IdentifyQRCode"]
- action:@selector(tweakIdentifyQRCode:)
- keyEquivalent:@"i"];
- item.target = self;
- item;
- })];
- break;
- }
- case MessageDataTypeSticker: {
- [menu addItem:NSMenuItem.separatorItem];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.ExportSticker"]
- action:@selector(tweakExportSticker:)
- keyEquivalent:@"e"];
- item.target = self;
- item;
- })];
- break;
- }
- case MessageDataTypeLocation: {
- [menu addItem:NSMenuItem.separatorItem];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInGoogleMaps"]
- action:@selector(tweakOpenMaps:)
- keyEquivalent:@""];
- item.target = self;
- item.tag = OpenMapMenuTypeGoogleMaps;
- item;
- })];
- [menu addItem:({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInAmap"]
- action:@selector(tweakOpenMaps:)
- keyEquivalent:@""];
- item.target = self;
- item.tag = OpenMapMenuTypeAmap;
- item;
- })];
- break;
- }
- default: {
- break;
- }
- }
- }
- return menu;
-}
-
-- (void)tweakCopyLink:(NSMenuItem *)sender {
- ReaderWrap *wrap = sender.target;
- if (!wrap) {
- return;
- }
- if (wrap.m_nsUrl) {
- [NSPasteboard.generalPasteboard clearContents];
- [NSPasteboard.generalPasteboard setString:wrap.m_nsUrl forType:NSStringPboardType];
- }
-}
-
-- (void)tweakOpenLink:(NSMenuItem *)sender {
- ReaderWrap *wrap = sender.target;
- if (!wrap) {
- return;
- }
- if (wrap.m_nsUrl && [NSURL URLWithString:wrap.m_nsUrl]) {
- [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:wrap.m_nsUrl]];
- }
-}
-
-- (void)tweakIdentifyQRCode:(NSMenuItem *)sender {
- NSImage *image = ((MMImageMessageCellView *)self).displayedImage;
- if (image) {
- NSData *imageData = [image TIFFRepresentation];
- CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
- NSArray *results = [detector featuresInImage:[CIImage imageWithData:imageData]];
- if (results.count) {
- CIQRCodeFeature *result = results.firstObject;
- NSString *content = result.messageString;
- if (content.length) {
- NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
- [pasteboard clearContents];
- [pasteboard setString:content forType:NSStringPboardType];
- [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:({
- NSUserNotification *notification = [[NSUserNotification alloc] init];
- notification.informativeText = [NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.IdentifyQRCodeNotification"];
- notification;
- })];
- }
- }
- }
-}
-
-- (void)tweakExportSticker:(NSMenuItem *)sender {
- MMMessageCellView *cell = (MMMessageCellView *)sender.target;
- MessageData *messageData = cell.messageTableItem.message;
- NSString *localID = [messageData savingImageFileNameWithLocalID];
- NSString *md5 = [NSDictionary dictionaryWithXMLString:[messageData.msgContent componentsSeparatedByString:@"\n"].lastObject][@"emoji"][@"_md5"];
- if (!localID.length || !md5.length) {
- return;
- }
- NSSavePanel *panel = [NSSavePanel savePanel];
- [panel setNameFieldStringValue:localID];
- [panel setAllowsOtherFileTypes:YES];
- [panel setAllowedFileTypes:@[@"gif"]];
- [panel setExtensionHidden:NO];
- [panel setCanCreateDirectories:YES];
- [panel beginSheetModalForWindow:cell.window completionHandler:^(NSModalResponse result) {
- if (result == NSModalResponseOK) {
- NSString *path = panel.URL.path;
- MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
- EmoticonMgr *emoticonMgr = [serviceCenter getService:objc_getClass("EmoticonMgr")];
- NSData *stickerData = [emoticonMgr getEmotionDataWithMD5:md5];
- [stickerData writeToFile:path atomically:YES];
- }
- }];
-}
-
-- (void)tweakOpenMaps:(NSMenuItem *)sender {
- MMMessageCellView *cell = (MMMessageCellView *)sender.target;
-
- NSURL *url = ({
- NSURL *url = nil;
- NSDictionary *location = [NSDictionary dictionaryWithXMLString:cell.messageTableItem.message.msgContent][@"location"];
- id x = location[@"_x"];
- id y = location[@"_y"];
- if (x && y) {
- switch (sender.tag) {
- case OpenMapMenuTypeGoogleMaps:
- url = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.google.com/maps/search/?api=1&query=%@,%@", x, y]];
- break;
- case OpenMapMenuTypeAmap:
- url = [NSURL URLWithString:[NSString stringWithFormat:@"https://uri.amap.com/marker?position=%@,%@", y, x]];
- break;
- default:
- break;
- }
- }
- url;
- });
-
- if (url) {
- [NSWorkspace.sharedWorkspace openURL:url];
- }
-}
-
-@end
diff --git a/WeChatTweak/Controller/Base.lproj/TweakPreferencesController.xib b/WeChatTweak/Controller/Base.lproj/TweakPreferencesController.xib
deleted file mode 100644
index 9ab82dc..0000000
--- a/WeChatTweak/Controller/Base.lproj/TweakPreferencesController.xib
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/WeChatTweak/Controller/TweakPreferencesController.h b/WeChatTweak/Controller/TweakPreferencesController.h
deleted file mode 100644
index d0c1b58..0000000
--- a/WeChatTweak/Controller/TweakPreferencesController.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// TweakPreferencesController.h
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/12.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-
-@interface TweakPreferencesController : NSViewController
-
-@end
diff --git a/WeChatTweak/Controller/TweakPreferencesController.m b/WeChatTweak/Controller/TweakPreferencesController.m
deleted file mode 100644
index 69c6d8d..0000000
--- a/WeChatTweak/Controller/TweakPreferencesController.m
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// TweakPreferencesController.m
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/12.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "TweakPreferencesController.h"
-#import "NSBundle+WeChatTweak.h"
-
-@interface TweakPreferencesController ()
-
-@property (weak) IBOutlet NSPopUpButton *notificationTypeButton;
-@property (weak) IBOutlet NSColorWell *maskColorWell;
-
-@end
-
-@implementation TweakPreferencesController
-
-- (void)viewDidLoad {
- [super viewDidLoad];
- [NSColorPanel.sharedColorPanel setShowsAlpha:YES];
-}
-
-- (void)viewWillAppear {
- [super viewWillAppear];
- [self reloadData];
-}
-
-- (void)reloadData {
- self.maskColorWell.color = WeChatTweak.maskColor;
- [self.notificationTypeButton selectItemAtIndex:WeChatTweak.notificationType];
-}
-
-#pragma mark - Event method
-
-- (IBAction)switchNotificationTypeAction:(NSPopUpButton *)sender {
- WeChatTweak.notificationType = sender.indexOfSelectedItem;
-}
-
-- (IBAction)changeMaskColorAction:(NSColorWell *)sender {
- WeChatTweak.maskColor = sender.color;
-}
-
-#pragma mark - MASPreferencesViewController
-
-- (NSString *)identifier {
- return @"tweak";
-}
-
-- (NSString *)toolbarItemLabel {
- return @"Tweak";
-}
-
-- (NSImage *)toolbarItemImage {
- return [[NSBundle tweakBundle] imageForResource:@"Prefs-Tweak"];
-}
-
-- (BOOL)hasResizableWidth {
- return NO;
-}
-
-- (BOOL)hasResizableHeight {
- return NO;
-}
-
-@end
diff --git a/WeChatTweak/Controller/en.lproj/TweakPreferencesController.strings b/WeChatTweak/Controller/en.lproj/TweakPreferencesController.strings
deleted file mode 100644
index 75de18b..0000000
--- a/WeChatTweak/Controller/en.lproj/TweakPreferencesController.strings
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/* Class = "NSTextFieldCell"; title = "Message recalled notification:"; ObjectID = "UKv-CM-nGt"; */
-"UKv-CM-nGt.title" = "Message recalled notification:";
-
-/* Class = "NSMenuItem"; title = "Disabled"; ObjectID = "Uk9-Oc-Jtv"; */
-"Uk9-Oc-Jtv.title" = "Disabled";
-
-/* Class = "NSMenuItem"; title = "All"; ObjectID = "da4-aJ-lEy"; */
-"da4-aJ-lEy.title" = "All";
-
-/* Class = "NSMenuItem"; title = "Inherited"; ObjectID = "gec-CY-E1x"; */
-"gec-CY-E1x.title" = "Inherited";
-
-/* Class = "NSTextFieldCell"; title = "Recall mask color:"; ObjectID = "3xl-c5-YvI"; */
-"3xl-c5-YvI.title" = "Recall mask color:";
diff --git a/WeChatTweak/Controller/zh-Hans.lproj/TweakPreferencesController.strings b/WeChatTweak/Controller/zh-Hans.lproj/TweakPreferencesController.strings
deleted file mode 100644
index b35413d..0000000
--- a/WeChatTweak/Controller/zh-Hans.lproj/TweakPreferencesController.strings
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/* Class = "NSTextFieldCell"; title = "Message recalled notification:"; ObjectID = "UKv-CM-nGt"; */
-"UKv-CM-nGt.title" = "消息撤回通知:";
-
-/* Class = "NSMenuItem"; title = "Disabled"; ObjectID = "Uk9-Oc-Jtv"; */
-"Uk9-Oc-Jtv.title" = "关闭";
-
-/* Class = "NSMenuItem"; title = "All"; ObjectID = "da4-aJ-lEy"; */
-"da4-aJ-lEy.title" = "全部接收";
-
-/* Class = "NSMenuItem"; title = "Inherited"; ObjectID = "gec-CY-E1x"; */
-"gec-CY-E1x.title" = "跟随聊天设置";
-
-/* Class = "NSTextFieldCell"; title = "Recall mask color:"; ObjectID = "3xl-c5-YvI"; */
-"3xl-c5-YvI.title" = "撤回遮罩颜色";
diff --git a/WeChatTweak/Controller/zh-Hant.lproj/TweakPreferencesController.strings b/WeChatTweak/Controller/zh-Hant.lproj/TweakPreferencesController.strings
deleted file mode 100644
index a44fa1d..0000000
--- a/WeChatTweak/Controller/zh-Hant.lproj/TweakPreferencesController.strings
+++ /dev/null
@@ -1,15 +0,0 @@
-
-/* Class = "NSTextFieldCell"; title = "Message recalled notification:"; ObjectID = "UKv-CM-nGt"; */
-"UKv-CM-nGt.title" = "消息撤回通知:";
-
-/* Class = "NSMenuItem"; title = "Disabled"; ObjectID = "Uk9-Oc-Jtv"; */
-"Uk9-Oc-Jtv.title" = "關閉";
-
-/* Class = "NSMenuItem"; title = "All"; ObjectID = "da4-aJ-lEy"; */
-"da4-aJ-lEy.title" = "全部接收";
-
-/* Class = "NSMenuItem"; title = "Inherited"; ObjectID = "gec-CY-E1x"; */
-"gec-CY-E1x.title" = "跟隨聊天設置";
-
-/* Class = "NSTextFieldCell"; title = "Recall mask color:"; ObjectID = "3xl-c5-YvI"; */
-"3xl-c5-YvI.title" = "撤回遮罩顏色";
diff --git a/WeChatTweak/Directory.m b/WeChatTweak/Directory.m
deleted file mode 100644
index 7cbad49..0000000
--- a/WeChatTweak/Directory.m
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Directory.m
-// WeChatTweak
-//
-// Created by Sunny Young on 2022/2/1.
-// Copyright © 2022 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-#import "fishhook.h"
-
-static NSString *(*original_NSHomeDirectory)(void);
-static NSArray *(*original_NSSearchPathForDirectoriesInDomains)(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);
-NSString *tweak_NSHomeDirectory(void) {
- return [original_NSHomeDirectory() stringByAppendingPathComponent:@"/Library/Containers/com.tencent.xinWeChat/Data/"];
-}
-NSArray *tweak_NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde) {
- if (domainMask == NSUserDomainMask) {
- NSMutableArray *directories = [original_NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde) mutableCopy];
- [directories enumerateObjectsUsingBlock:^(NSString * _Nonnull object, NSUInteger index, BOOL * _Nonnull stop) {
- switch (directory) {
- case NSDocumentDirectory: directories[index] = [tweak_NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; break;
- case NSLibraryDirectory: directories[index] = [tweak_NSHomeDirectory() stringByAppendingPathComponent:@"Library"]; break;
- case NSApplicationSupportDirectory: directories[index] = [tweak_NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support"]; break;
- case NSCachesDirectory: directories[index] = [tweak_NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"]; break;
- default: break;
- }
- }];
- return directories;
- } else {
- return original_NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde);
- }
-}
-
-static void __attribute__((constructor)) tweak(void) {
- // Global Function Hook
- rebind_symbols((struct rebinding[2]) {
- { "NSHomeDirectory", tweak_NSHomeDirectory, (void *)&original_NSHomeDirectory },
- { "NSSearchPathForDirectoriesInDomains", tweak_NSSearchPathForDirectoriesInDomains, (void *)&original_NSSearchPathForDirectoriesInDomains }
- }, 2);
-}
diff --git a/WeChatTweak/MultipleInstances.m b/WeChatTweak/MultipleInstances.m
deleted file mode 100644
index ef092d0..0000000
--- a/WeChatTweak/MultipleInstances.m
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// MultipleInstances.m
-// WeChatTweak
-//
-// Created by Sunny Young on 2022/2/1.
-// Copyright © 2022 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-#import "NSBundle+WeChatTweak.h"
-
-@implementation NSObject (MultipleInstances)
-
-static void __attribute__((constructor)) tweak(void) {
- [objc_getClass("CUtility") jr_swizzleClassMethod:NSSelectorFromString(@"HasWechatInstance") withClassMethod:@selector(tweak_HasWechatInstance) error:nil];
- [objc_getClass("NSRunningApplication") jr_swizzleClassMethod:NSSelectorFromString(@"runningApplicationsWithBundleIdentifier:") withClassMethod:@selector(tweak_runningApplicationsWithBundleIdentifier:) error:nil];
- [objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationDockMenu:") withMethod:@selector(tweak_applicationDockMenu:) error:nil];
-}
-
-+ (BOOL)tweak_HasWechatInstance {
- return NO;
-}
-
-+ (NSArray *)tweak_runningApplicationsWithBundleIdentifier:(NSString *)bundleIdentifier {
- if ([bundleIdentifier isEqualToString:NSBundle.mainBundle.bundleIdentifier] ) {
- return @[NSRunningApplication.currentApplication];
- } else {
- return [self tweak_runningApplicationsWithBundleIdentifier:bundleIdentifier];
- }
-}
-
-- (NSMenu *)tweak_applicationDockMenu:(NSApplication *)sender {
- NSMenu *menu = [self tweak_applicationDockMenu:sender];
- NSMenuItem *menuItem = ({
- NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.Title.LoginAnotherAccount"]
- action:@selector(openNewWeChatInstace:)
- keyEquivalent:@""];
- item.tag = 9527;
- item;
- });
- __block BOOL added = NO;
- [menu.itemArray enumerateObjectsUsingBlock:^(NSMenuItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- if (obj.tag == 9527) {
- *stop = added = YES;
- }
- }];
- if (!added) {
- [menu insertItem:menuItem atIndex:0];
- }
- return menu;
-}
-
-- (void)openNewWeChatInstace:(id)sender {
- NSString *applicationPath = NSBundle.mainBundle.bundlePath;
- NSTask *task = [[NSTask alloc] init];
- task.launchPath = @"/usr/bin/open";
- task.arguments = @[@"-n", applicationPath];
- [task launch];
- [task waitUntilExit];
-}
-
-@end
diff --git a/WeChatTweak/PreferencesWindow.m b/WeChatTweak/PreferencesWindow.m
deleted file mode 100644
index c8f4e69..0000000
--- a/WeChatTweak/PreferencesWindow.m
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// PreferencesWindow.m
-// WeChatTweak
-//
-// Created by Sunny Young on 2022/2/1.
-// Copyright © 2022 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-#import "NSBundle+WeChatTweak.h"
-#import "TweakPreferencesController.h"
-
-@implementation NSObject (PreferencesWindow)
-
-#pragma mark - Constructor
-
-static void __attribute__((constructor)) tweak(void) {
- [objc_getClass("MASPreferencesWindowController") jr_swizzleMethod:NSSelectorFromString(@"initWithViewControllers:") withMethod:@selector(tweak_initWithViewControllers:) error:nil];
-}
-
-#pragma mark - Preferences Window
-
-- (id)tweak_initWithViewControllers:(NSArray *)arg1 {
- NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:arg1];
- TweakPreferencesController *controller = [[TweakPreferencesController alloc] initWithNibName:nil bundle:[NSBundle tweakBundle]];
- [viewControllers addObject:controller];
- return [self tweak_initWithViewControllers:viewControllers];
-}
-
-@end
-
diff --git a/WeChatTweak/Resources/Prefs-Tweak.tiff b/WeChatTweak/Resources/Prefs-Tweak.tiff
deleted file mode 100644
index 45c64f9..0000000
Binary files a/WeChatTweak/Resources/Prefs-Tweak.tiff and /dev/null differ
diff --git a/WeChatTweak/Supporting Files/WeChatTweakHeaders.h b/WeChatTweak/Supporting Files/WeChatTweakHeaders.h
deleted file mode 100644
index 1186a58..0000000
--- a/WeChatTweak/Supporting Files/WeChatTweakHeaders.h
+++ /dev/null
@@ -1,200 +0,0 @@
-//
-// WeChatTweakHeaders.h
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/11.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import
-#import
-#import
-#import
-
-typedef NS_ENUM(unsigned int, MessageDataType) {
- MessageDataTypeText = 1,
- MessageDataTypeImage = 3,
- MessageDataTypeVoice = 34,
- MessageDataTypeVideo = 43,
- MessageDataTypeSticker = 47,
- MessageDataTypeLocation = 48,
- MessageDataTypeAppUrl = 49,
- MessageDataTypePrompt = 10000
-};
-
-@interface NSString (MD5)
-
-- (NSString *)md5String;
-
-@end
-
-@interface WeChat : NSObject
-
-+ (instancetype)sharedInstance;
-- (void)lock:(id)block;
-- (void)showMainWindow;
-- (void)startANewChatWithContact:(id)contact;
-
-@end
-
-@interface PathUtility : NSObject
-
-+ (NSString *)GetCurUserDocumentPath;
-
-@end
-
-@interface MMSearchResultItem : NSObject
-
-@property(nonatomic) unsigned long long type; // 0 is single chat, 1 is group chat
-@property(readonly, nonatomic) NSString *identifier;
-
-@end
-
-@interface MessageData: NSObject
-
-@property(nonatomic) MessageDataType messageType;
-@property(nonatomic) unsigned int msgStatus;
-@property(nonatomic) long long mesSvrID;
-@property(retain, nonatomic) NSString *toUsrName;
-@property(retain, nonatomic) NSString *fromUsrName;
-@property(retain, nonatomic) NSString *msgContent;
-@property(nonatomic) unsigned int msgCreateTime;
-@property(nonatomic) unsigned int mesLocalID;
-
-- (instancetype)initWithMsgType:(long long)arg1;
-- (BOOL)isSendFromSelf;
-- (id)getChatNameForCurMsg;
-- (id)savingImageFileNameWithLocalID;
-
-@end
-
-@interface ReaderWrap : NSObject
-
-@property(retain, nonatomic) NSString *m_nsTitle;
-@property(retain, nonatomic) NSString *m_nsUrl;
-
-@end
-
-@interface WCContactData : NSObject
-
-@property(nonatomic) unsigned int m_uiCertificationFlag;
-@property(retain, nonatomic) NSString *m_nsHeadImgUrl;
-@property(retain, nonatomic) NSString *m_nsNickName;
-@property(retain, nonatomic) NSString *m_nsUsrName;
-@property(retain, nonatomic) NSString *m_nsAliasName;
-@property(retain, nonatomic) NSString *m_nsRemark;
-@property(retain, nonatomic) NSString *m_nsFullPY;
-@property(retain, nonatomic) NSString *m_nsRemarkPYShort;
-@property(retain, nonatomic) NSString *m_nsRemarkPYFull;
-@property(retain, nonatomic) NSString *wt_avatarPath;
-
-- (BOOL)isChatStatusNotifyOpen;
-
-@end
-
-@interface ContactStorage : NSObject
-
-- (WCContactData *)GetContact:(NSString *)session;
-- (NSArray *)GetAllFriendContacts;
-
-@end
-
-@interface GroupStorage: NSObject
-
-- (WCContactData *)GetGroupContact:(NSString *)session;
-- (NSArray *)GetAllGroups;
-- (NSArray *)GetGroupContactList:(NSInteger)arg1 ContactType:(NSInteger)arg2;
-
-@end
-
-@interface MMServiceCenter : NSObject
-
-+ (id)defaultCenter;
-- (id)getService:(Class)name;
-
-@end
-
-@interface MMAvatarService: NSObject
-
-- (NSString *)avatarCachePath;
-
-@end
-
-@protocol MASPreferencesViewController
-
-@property(readonly, nonatomic) NSString *toolbarItemLabel;
-@property(readonly, nonatomic) NSImage *toolbarItemImage;
-@property(readonly, nonatomic) NSString *identifier;
-
-@optional
-@property(readonly, nonatomic) BOOL hasResizableHeight;
-@property(readonly, nonatomic) BOOL hasResizableWidth;
-
-@end
-
-@interface MASPreferencesWindowController: NSWindowController
-
-- (id)initWithViewControllers:(NSArray *)arg1;
-
-@end
-
-@interface MMMessageTableItem : NSObject
-
-@property(retain, nonatomic) MessageData *message;
-
-@end
-
-@interface MMMessageCellView : NSTableCellView
-
-@property(retain, nonatomic) NSView *avatarImgView;
-@property(retain, nonatomic) MMMessageTableItem *messageTableItem;
-
-@end
-
-@interface MMImageMessageCellView : MMMessageCellView
-
-@property(retain, nonatomic) NSImage *displayedImage;
-
-@end
-
-@interface MMAppSingleReaderMessageCellView : MMMessageCellView
-
-@property(retain, nonatomic) ReaderWrap *readerData;
-
-@end
-
-@interface MMAppMultipleReaderMessageCellView : MMMessageCellView
-
-@property(retain, nonatomic) NSArray *readerMessages;
-@property(assign, nonatomic) NSUInteger selectedReaderWrapIndex;
-
-@end
-
-@interface MMService : NSObject
-
-@end
-
-@interface EmoticonMgr : MMService
-
-- (id)getEmotionDataWithMD5:(id)arg1;
-
-@end
-
-@interface FFProcessReqsvrZZ : NSObject
-
-- (id)GetMsgData:(id)arg2 localId:(long long)arg3;
-- (id)GetMsgData:(id)arg2 svrId:(long long)arg3;
-- (void)AddLocalMsg:(id)arg2 msgData:(id)arg3;
-- (void)ModifyMsgData:(id)arg2 msgData:(id)arg3;
-- (void)notifyAddMsgOnMainThread:(id)arg2 msgData:(id)arg3;
-- (void)notifyModMsgOnMainThread:(id)arg2 msgData:(id)arg3;
-- (void)notifyDelMsgOnMainThread:(id)arg2 msgData:(id)arg3 isRevoke:(BOOL)arg4;
-- (void)notifyUIAndSessionOnMainThread:(id)arg2 withMsg:(id)arg3;
-
-@end
-
-@interface NSDictionary (XMLDictionary)
-
-+ (id)dictionaryWithXMLString:(id)arg1;
-
-@end
diff --git a/WeChatTweak/Supporting Files/en.lproj/Localizable.strings b/WeChatTweak/Supporting Files/en.lproj/Localizable.strings
deleted file mode 100644
index 1f6f638..0000000
--- a/WeChatTweak/Supporting Files/en.lproj/Localizable.strings
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Localizable.strings
- WeChatTweak
-
- Created by Sunny Young on 2018/6/30.
- Copyright © 2018 Sunnyyoung. All rights reserved.
-*/
-
-"Tweak.Title.LoginAnotherAccount" = "Login new account";
-"Tweak.Title.Group" = "Group";
-"Tweak.Message.InterceptedARecalledMessage" = "[Intercepted a recalled message]\n%@";
-"Tweak.Message.Recalled" = "recalled";
-"Tweak.Message.RecalledMark" = "[Recalled]";
-"Tweak.Message.Image" = "Image";
-"Tweak.Message.Voice" = "Voice";
-"Tweak.Message.Video" = "Video";
-"Tweak.Message.Sticker" = "Sticker";
-"Tweak.Message.Link" = "Link";
-"Tweak.Message.AMessage" = "a message";
-"Tweak.MessageMenuItem.CopyLink" = "Copy Link";
-"Tweak.MessageMenuItem.OpenInBrowser" = "Open In Browser";
-"Tweak.MessageMenuItem.IdentifyQRCode" = "Identify QRCode";
-"Tweak.MessageMenuItem.IdentifyQRCodeNotification" = "The result of the recognition has been copied to the pasteboard";
-"Tweak.MessageMenuItem.ExportSticker" = "Export Sticker";
-"Tweak.MessageMenuItem.OpenInGoogleMaps" = "Open in Google Maps";
-"Tweak.MessageMenuItem.OpenInAmap" = "Open in Amap";
diff --git a/WeChatTweak/Supporting Files/zh-Hans.lproj/Localizable.strings b/WeChatTweak/Supporting Files/zh-Hans.lproj/Localizable.strings
deleted file mode 100644
index 4a722b0..0000000
--- a/WeChatTweak/Supporting Files/zh-Hans.lproj/Localizable.strings
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Localizable.strings
- WeChatTweak
-
- Created by Sunny Young on 2018/6/30.
- Copyright © 2018 Sunnyyoung. All rights reserved.
-*/
-
-"Tweak.Title.LoginAnotherAccount" = "登录新的账号";
-"Tweak.Title.Group" = "群组";
-"Tweak.Message.InterceptedARecalledMessage" = "[已拦截一条撤回消息]\n%@";
-"Tweak.Message.Recalled" = "撤回了";
-"Tweak.Message.RecalledMark" = "[已撤回]";
-"Tweak.Message.Image" = "图片";
-"Tweak.Message.Voice" = "语音";
-"Tweak.Message.Video" = "视频";
-"Tweak.Message.Sticker" = "表情";
-"Tweak.Message.Link" = "链接";
-"Tweak.Message.AMessage" = "一条消息";
-"Tweak.MessageMenuItem.CopyLink" = "复制链接";
-"Tweak.MessageMenuItem.OpenInBrowser" = "使用浏览器打开";
-"Tweak.MessageMenuItem.IdentifyQRCode" = "识别二维码";
-"Tweak.MessageMenuItem.IdentifyQRCodeNotification" = "识别结果已复制到粘贴板";
-"Tweak.MessageMenuItem.ExportSticker" = "导出表情";
-"Tweak.MessageMenuItem.OpenInGoogleMaps" = "使用谷歌地图打开";
-"Tweak.MessageMenuItem.OpenInAmap" = "使用高德地图打开";
diff --git a/WeChatTweak/Supporting Files/zh-Hant.lproj/Localizable.strings b/WeChatTweak/Supporting Files/zh-Hant.lproj/Localizable.strings
deleted file mode 100644
index 764105b..0000000
--- a/WeChatTweak/Supporting Files/zh-Hant.lproj/Localizable.strings
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- Localizable.strings
- WeChatTweak
-
- Created by Sunny Young on 2018/6/30.
- Copyright © 2018 Sunnyyoung. All rights reserved.
-*/
-
-"Tweak.Title.LoginAnotherAccount" = "登錄新的賬號";
-"Tweak.Title.Group" = "群組";
-"Tweak.Message.InterceptedARecalledMessage" = "[已攔截壹條撤回消息]\n%@";
-"Tweak.Message.Recalled" = "撤回了";
-"Tweak.Message.RecalledMark" = "[已撤回]";
-"Tweak.Message.Image" = "图片";
-"Tweak.Message.Voice" = "语音";
-"Tweak.Message.Video" = "视频";
-"Tweak.Message.Sticker" = "表情";
-"Tweak.Message.Link" = "链接";
-"Tweak.Message.AMessage" = "一条消息";
-"Tweak.MessageMenuItem.CopyLink" = "複製鏈接";
-"Tweak.MessageMenuItem.OpenInBrowser" = "使用瀏覽器打開";
-"Tweak.MessageMenuItem.IdentifyQRCode" = "識別QRCode";
-"Tweak.MessageMenuItem.IdentifyQRCodeNotification" = "識別結果已復製到粘貼板";
-"Tweak.MessageMenuItem.ExportSticker" = "導出貼圖";
-"Tweak.MessageMenuItem.OpenInGoogleMaps" = "使用谷歌地圖打開";
-"Tweak.MessageMenuItem.OpenInAmap" = "使用高德地圖打開";
diff --git a/WeChatTweak/WeChatTweak.h b/WeChatTweak/WeChatTweak.h
deleted file mode 100644
index 1b14086..0000000
--- a/WeChatTweak/WeChatTweak.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// WeChatTweak.h
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/11.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweakHeaders.h"
-
-FOUNDATION_EXPORT double WeChatTweakVersionNumber;
-FOUNDATION_EXPORT const unsigned char WeChatTweakVersionString[];
-
-typedef NS_ENUM(NSUInteger, WeChatTweakNotificationType) {
- WeChatTweakNotificationTypeInherited = 0,
- WeChatTweakNotificationTypeReceiveAll,
- WeChatTweakNotificationTypeDisable
-};
-
-@interface WeChatTweak : NSObject
-
-@property (class, assign) WeChatTweakNotificationType notificationType;
-@property (class, nonnull) NSColor *maskColor;
-
-@end
diff --git a/WeChatTweak/WeChatTweak.m b/WeChatTweak/WeChatTweak.m
deleted file mode 100755
index c7dc994..0000000
--- a/WeChatTweak/WeChatTweak.m
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// WeChatTweak.m
-// WeChatTweak
-//
-// Created by Sunnyyoung on 2017/8/11.
-// Copyright © 2017年 Sunnyyoung. All rights reserved.
-//
-
-#import "WeChatTweak.h"
-
-@implementation WeChatTweak
-
-+ (WeChatTweakNotificationType)notificationType {
- return [NSUserDefaults.standardUserDefaults integerForKey:@"WeChatTweakPreferenceRevokeNotificationTypeKey"];
-}
-
-+ (void)setNotificationType:(WeChatTweakNotificationType)notificationType {
- [NSUserDefaults.standardUserDefaults setInteger:notificationType forKey:@"WeChatTweakPreferenceRevokeNotificationTypeKey"];
-}
-
-+ (NSColor *)maskColor {
- NSData *data = [NSUserDefaults.standardUserDefaults objectForKey:@"WeChatTweakMaskColor"];
- return data ? [NSKeyedUnarchiver unarchiveObjectWithData:data] : [NSColor.systemYellowColor colorWithAlphaComponent:0.3];
-}
-
-+ (void)setMaskColor:(NSColor *)maskColor {
- NSData *data = [NSKeyedArchiver archivedDataWithRootObject:maskColor];
- [NSUserDefaults.standardUserDefaults setObject:data forKey:@"WeChatTweakMaskColor"];
-}
-
-@end
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..397df08
--- /dev/null
+++ b/config.json
@@ -0,0 +1,77 @@
+[
+ {
+ "version": "31927",
+ "targets": [
+ {
+ "identifier": "revoke",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "103dba3d0",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "startUpdater",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001ea41c",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "startBackgroundUpdatesCheck",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001ed3b4",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "checkForUpdates",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001ecf9c",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "enableAutoUpdate",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001ed920",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "automaticallyDownloadsUpdates",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001f6ee8",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ },
+ {
+ "identifier": "canCheckForUpdate",
+ "entries": [
+ {
+ "arch": "arm64",
+ "addr": "1001f6ef8",
+ "asm": "00008052C0035FD6"
+ }
+ ]
+ }
+ ]
+ }
+]
diff --git a/fishhook.podspec b/fishhook.podspec
deleted file mode 100644
index 8c8ade9..0000000
--- a/fishhook.podspec
+++ /dev/null
@@ -1,13 +0,0 @@
-Pod::Spec.new do |spec|
- spec.name = "fishhook"
- spec.version = "0.2"
- spec.license = { :type => "BSD", :file => "LICENSE" }
- spec.homepage = 'https://github.com/facebook/fishhook'
- spec.author = { "Facebook, Inc." => "https://github.com/facebook" }
- spec.summary = "A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS."
- spec.source = { :git => "https://github.com/facebook/fishhook.git", :tag => '0.2'}
- spec.source_files = "fishhook.{h,c}"
- spec.social_media_url = 'https://twitter.com/fbOpenSource'
-
- spec.macos.deployment_target = '10.9'
-end
diff --git a/insert_dylib b/insert_dylib
deleted file mode 100755
index 02dfc22..0000000
Binary files a/insert_dylib and /dev/null differ