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](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE) -[![README](https://img.shields.io/badge/README-English-blue.svg)](README-English.md) -[![README](https://img.shields.io/badge/README-中文-blue.svg)](README.md) -[![README](https://img.shields.io/badge/Telegram-WeChatTweak-brightgreen.svg)](https://t.me/wechattweak) - -A dynamic library tweak for WeChat macOS. - -![Overview](Screenshot/overview.jpg) - -## 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)]. - -[![Contributors](https://opencollective.com/WeChatTweak-macOS/contributors.svg?width=890&button=false)](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](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE) -[![README](https://img.shields.io/badge/README-English-blue.svg)](README-English.md) -[![README](https://img.shields.io/badge/README-中文-blue.svg)](README.md) [![README](https://img.shields.io/badge/Telegram-WeChatTweak-brightgreen.svg)](https://t.me/wechattweak) -微信 macOS 客户端增强 Tweak 动态库。 - -![Overview](Screenshot/overview.jpg) - ## 功能 -- 阻止消息撤回 - - 消息列表通知 - - 系统通知 - - 正常撤回自己发出的消息 -- 客户端无限多开 - - 右键 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