上一篇分析文章中已经罗列了工程中的所有依赖库的作用, 这篇文章的重点就是看 APP 中这些依赖库的结构.
在 Xcode 中可以看到 ShadowCoel Project 中有如下图所示的 Target 列表:
下面就分别来看这些 Target 及其作用.
ShadowCoel Target
ShadowCoel: APP Target, 即 iOS APP 的实现.
在 APP Target 中 Embedded Binaries 如下图所示:
在 APP Target 中 Linked Framework and Libraries 如下图所示:
PacketTunnel Target
PacketTunnel: 可执行的 APP Extension. 它的主要作用就是和 Network Extension framework 进行交互.
其中依赖如下所示:
可以在这个 Target 的 info.plist 中找到相关的配置:
NSExtensionPrincipalClass: 即实现 APP Extension 的主视图的类名称, 这里的值是 PacketTunnelProvider.
NSExtensionPointIdentifier: 这里的值是 com.apple.networkextension.packet-tunnel, 表示的是这个 APP Extension 是一个 Packet Tunnel Provider Extension, 这样它就可以对诸如系统的 HTTP 代理等进行配置, 详见苹果官方文档.
关于 APP Extension 的更多信息详见苹果 APP Extension 的官方文档.
PacketTunnelProvider
声明如下所示:
@import NetworkExtension; @interface PacketTunnelProvider : NEPacketTunnelProvider @end
功能的实现主要是重写父类的如下方法:
// Start the network tunnel. startTunnel(options:completionHandler:) // Stop the network tunnel. stopTunnel(with:completionHandler:) // Stop the network tunnel from the Packet Tunnel Provider. cancelTunnelWithError(_:)
之后会专门开一个文章对这个 Extension 的实现进行专门分析.
TodayWidget
可执行的 APP Extension, 在它的 info.plist 中有如下配置:
NSExtensionPointIdentifier 键的值是 com.apple.widget-extension, 表明这个 Extension 是一个 Today Extension, 如下表所示:
通过这个 APP Extension, 就具备了在 Today 中显示相关 Widget 视图的能力.
ShadowCoelLibrary
这个 Target 的主要功能是提供和代理功能相关的一些辅助功能. 之后会专门进行分析.
PacketProcessor
数据包处理器, 里面依赖了一个 tun2socks-iOS.
PacketProcessor 提供了如下接口:
#define TunnelMTU 1600 #define kTun2SocksStoppedNotification @"kTun2SocksStoppedNotification" @interface TunnelInterface : NSObject + (TunnelInterface *) sharedInterface; - (instancetype) init NS_UNAVAILABLE; - (NSError *) setupWithPacketTunnelFlow:(NEPacketTunnelFlow *)packetFlow; - (void) processPackets; - (void) writePacket:(NSData *)packet; - (void) startTun2Socks:(int)socksServerPort; - (void) stop; @end
之后会专门进行分析.
ShadowCoelModel
在其中建立了 APP 中的核心数据结构, 比如:
public enum ProxyType: String { case Shadowsocks = "Shadowsocks" case ShadowsocksR = "ShadowsocksR" case V2ray = "V2ray" case Trojan = "Trojan" case GfwPress = "GFW.Press" case Http = "HTTP" case Https = "HTTPS" case Http2 = "HTTP2" case SSH = "SSH" case Socks4 = "Socks4" case Socks4a = "Socks4a" case Socks5 = "Socks5" case Socks5OverTls = "Socks5OverTLS" case Sni = "SNI" case Quic = "QUIC" case None = "None" }
详细的内容之后再分析.
ShadowCoelBase
提供其他辅助功能:
#import "ShadowCoel.h" #import "JSONUtils.h" #import "NSError+Helper.h" #import "Settings.h" #import "InfoInternal.h" #import "NSString+Localize.h"
比如 ShadowCoel 类提供的功能如下:
@interface ShadowCoel : NSObject + (NSString * _Nonnull)sharedGroupIdentifier; + (NSURL * _Nonnull)sharedUrl; + (NSURL * _Nonnull)sharedDatabaseUrl; + (NSUserDefaults * _Nonnull)sharedUserDefaults; + (NSURL * _Nonnull)sharedGeneralConfUrl; + (NSURL * _Nonnull)sharedSocksConfUrl; + (NSURL * _Nonnull)sharedProxyConfUrl; + (NSURL * _Nonnull)sharedHttpProxyConfUrl; + (NSURL * _Nonnull)sharedLogUrl; @end
详细的内容之后再分析.
阶段性总结
从上面两篇文章的分析, 可以看到, APP target 仅提供一个设置入口, 实际的代理配置主要通过 PacketTunnel 这个 APP Extension 来完成. 在其中启动 ss-local. 并通过进程间消息传递和 APP target, Today Extension 进行通信.
从下一篇文章开始, 将会介绍整个模仿实现的过程(开始会介绍整体需求获取和分析的过程).