Full Code of ToBeDefined/TLocationPlugin for AI

master 555c05644eb6 cached
77 files
330.8 KB
99.3k tokens
12 symbols
1 requests
Download .txt
Showing preview only (358K chars total). Download the full file or copy to clipboard to get everything.
Repository: ToBeDefined/TLocationPlugin
Branch: master
Commit: 555c05644eb6
Files: 77
Total size: 330.8 KB

Directory structure:
gitextract_c9p7_8y9/

├── .gitignore
├── README.md
├── RunScript/
│   ├── build_all.sh
│   ├── devices_arm_info.sh
│   ├── env.sh
│   ├── inject.sh
│   └── inject_app_icon.py
├── TLocationPlugin/
│   ├── Info.plist
│   ├── NSObject+TLocationPlugin.h
│   ├── NSObject+TLocationPlugin.m
│   ├── Others/
│   │   ├── TLocationManager.h
│   │   ├── TLocationManager.m
│   │   ├── TLocationModel.h
│   │   ├── TLocationModel.m
│   │   ├── TLocationPluginLocationConverter.h
│   │   └── TLocationPluginLocationConverter.m
│   ├── TLocationPlugin.h
│   ├── TSafeRuntimeCFunc.h
│   ├── TSafeRuntimeCFunc.m
│   ├── Tools/
│   │   ├── CALayer+TLocationPlugin.h
│   │   ├── CALayer+TLocationPlugin.m
│   │   ├── NSBundle+TLocationPlugin.h
│   │   ├── NSBundle+TLocationPlugin.m
│   │   ├── TAlertController.h
│   │   ├── TAlertController.m
│   │   ├── TLocationDefine.h
│   │   ├── UIApplication+TLocationPlugin.h
│   │   ├── UIApplication+TLocationPlugin.m
│   │   ├── UIImage+TLocationPlugin.h
│   │   ├── UIImage+TLocationPlugin.m
│   │   ├── UITableView+TLocationPlugin.h
│   │   ├── UITableView+TLocationPlugin.m
│   │   ├── UIViewController+TLocationPlugin.h
│   │   ├── UIViewController+TLocationPlugin.m
│   │   ├── UIWindow+TLocationPluginToast.h
│   │   ├── UIWindow+TLocationPluginToast.m
│   │   ├── UIWindow+TLocationPluginTouch.h
│   │   └── UIWindow+TLocationPluginTouch.m
│   └── ViewControllerAndViews/
│       ├── TAddLocationDataViewController.h
│       ├── TAddLocationDataViewController.m
│       ├── TAddLocationDataViewController.xib
│       ├── TBaseViewController.h
│       ├── TBaseViewController.m
│       ├── TLocationChangeAppICONViewController.h
│       ├── TLocationChangeAppICONViewController.m
│       ├── TLocationChangeAppICONViewController.xib
│       ├── TLocationNavigationController.h
│       ├── TLocationNavigationController.m
│       ├── TLocationSettingViewController.h
│       ├── TLocationSettingViewController.m
│       ├── TLocationSettingViewController.xib
│       ├── TLocationTableViewCell.h
│       ├── TLocationTableViewCell.m
│       ├── TSelectLocationDataViewController.h
│       ├── TSelectLocationDataViewController.m
│       └── TSelectLocationDataViewController.xib
├── TLocationPlugin.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   └── xcshareddata/
│   │       └── IDEWorkspaceChecks.plist
│   └── xcshareddata/
│       └── xcschemes/
│           ├── TLocationPlugin.xcscheme
│           └── TestLocationPlugin.xcscheme
├── TestLocationPlugin/
│   ├── AppDelegate.h
│   ├── AppDelegate.m
│   ├── Assets.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   └── Contents.json
│   ├── Base.lproj/
│   │   ├── LaunchScreen.storyboard
│   │   └── Main.storyboard
│   ├── Info.plist
│   ├── ViewController.h
│   ├── ViewController.m
│   └── main.m
├── requirements.txt
└── yololib/
    ├── README.md
    ├── main.m
    └── yololib.xcodeproj/
        ├── project.pbxproj
        └── project.xcworkspace/
            ├── contents.xcworkspacedata
            └── xcshareddata/
                └── IDEWorkspaceChecks.plist

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
#########################
# .gitignore file for Xcode4 / OS X Source projects
#
# NB: if you are storing "built" products, this WILL NOT WORK,
#   and you should use a different .gitignore (or none at all)
# This file is for SOURCE projects, where there are many extra
#   files that we want to exclude
#
# For updates, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
#########################

#####
# OS X temporary files that should never be committed

.DS_Store
*.swp
profile
*.ipa
*.mobileprovision
Payload/
TLocationPlugin.framework/

####
# Xcode temporary files that should never be committed
#
# NB: NIB/XIB files still exist even on Storyboard projects, so we want this...

*~.nib


####
# Xcode build files -
#
# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData"

DerivedData/

# NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build"

build/


#####
# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)
#
# This is complicated:
#
# SOMETIMES you need to put this file in version control.
# Apple designed it poorly - if you use "custom executables", they are
#  saved in this file.
# 99% of projects do NOT use those, so they do NOT want to version control this file.
#  ..but if you're in the 1%, comment out the line "*.pbxuser"

*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
#    NB: also, whitelist the default ones, some projects need to use these
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3


####
# Xcode 4 - semi-personal settings, often included in workspaces
#
# You can safely ignore the xcuserdata files - but do NOT ignore the files next to them
#

xcuserdata

####
# XCode 4 workspaces - more detailed
#
# Workspaces are important! They are a core feature of Xcode - don't exclude them :)
#
# Workspace layout is quite spammy. For reference:
#
# (root)/
#   (project-name).xcodeproj/
#     project.pbxproj
#     project.xcworkspace/
#       contents.xcworkspacedata
#       xcuserdata/
#         (your name)/xcuserdatad/
#     xcuserdata/
#       (your name)/xcuserdatad/
#
#
#
# Xcode 4 workspaces - SHARED
#
# This is UNDOCUMENTED (google: "developer.apple.com xcshareddata" - 0 results
# But if you're going to kill personal workspaces, at least keep the shared ones...
#
#
!xcshareddata

####
# XCode 4 build-schemes
#
# PRIVATE ones are stored inside xcuserdata
!xcschemes

####
# Xcode 4 - Deprecated classes
#
# Allegedly, if you manually "deprecate" your classes, they get moved here.
#
# We're using source-control, so this is a "feature" that we do not want!

*.moved-aside


####
# UNKNOWN: recommended by others, but I can't discover what these files are
#
# ...none. Everything is now explained.

*.svn
*.xccheckout
!Podfile.lock
Pods/
*.xcscmblueprint
.idea/
.vscode/
.atom/
infer-out/
*.ast.sh

================================================
FILE: README.md
================================================
### TLocationPlugin

> iOS 版本企业微信等软件虚拟定位,仅为个人学习 hook 以及移植非越狱手机实验(防hook 以及验证签名的App没有针对性处理)

### 功能

- [x] 设置定位信息

- [x] 保存当前地点定位信息

- [x] 地图搜索地点保存定位信息

- [x] 多个定位地点缓存

- [x] 设置是否 toast 提示定位信息

- [x] 更改 App 图标(iOS 13 暂未处理)

## 使用方法

- 依赖 `python3`处理 APP 图标, `pip3 install -r requirements.txt`

- 编译内部修改版本的`yololib`, 并将生成的 `yololib` 文件移动到`/usr/local/bin/`目录下(或者其他 PATH 目录内,可命令行执行 yololib 命令即可)

- 使用 [frida-ios-dump](https://github.com/AloneMonkey/frida-ios-dump)从越狱手机中 dump 出 ipa 文件,改名为`appname_origin.ipa` (`appname`为解压 App 后Payload 中.app 的名称,如企业微信为 wework_origin.ipa)

- 修改 `RunScript`文件夹中`env.sh`的环境变量`APP_NAME`和`BINARY_NAME`,`APP_NAME`是 App ipa 文件名(去除 `_origin.ipa`部分) ,`BINARY_NAME`是.app 中主二进制 target 名称(如企业微信都为 wework)

- Xcode运行 `RunScript` target (`Generic iOS Device`)

- 生成的文件为`appname_new.ipa`(如企业微信为 wework_new.ipa)

- 生成的 ipa 没有签名,可以使用 [fastlane](https://github.com/fastlane/fastlane) 进行重签名,重签名之后就可以安装到未越狱手机上了

- 安装之后,点击五次 App 的 Window (最好点击 NavigationBar),会打开定位设置界面

## 示例

- 设置定位界面

<img src="./img/1.jpeg" alt="选择虚拟定位" style="zoom:20%;" />

- 添加位置界面

<img src="./img/2.jpeg" alt="添加位置" style="zoom:20%;" />

- 设置界面

<img src="./img/3.jpeg" alt="设置" style="zoom:20%;" />

- 使用界面

<img src="./img/4.jpeg" alt="App使用" style="zoom:20%;" />





================================================
FILE: RunScript/build_all.sh
================================================
#!/usr/bin/env zsh --login

set -ex

CUR_DIR=$(realpath $(dirname "$0"))

source "$CUR_DIR/env.sh"

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"

# Step 1. Build Device and Simulator versions
xcodebuild -target "${FRAMEWORK_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${FRAMEWORK_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
    cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"
fi

# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
SIMULATOR_FRAMEWORK_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"      \
    "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"          
#    "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"   \
    

# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${FRAMEWORK_NAME}.framework" "${PROJECT_DIR}"

# Step 6. strip
strip -ur "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# Step 7. show nm
nm "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# Step 8. Convenience step to open the project's directory in Finder
rm -rf build

set +ex


================================================
FILE: RunScript/devices_arm_info.sh
================================================
#!/usr/bin/env zsh --login

# arm64 Support
export ARM64_DEVICES=\
'
"iPhone6,1",
"iPhone6,2",
"iPhone7,1",
"iPhone7,2",
"iPhone8,1",
"iPhone8,2",
"iPhone8,4",
"iPhone9,1",
"iPhone9,2",
"iPhone9,3",
"iPhone9,4",
"iPhone10,1",
"iPhone10,2",
"iPhone10,3",
"iPhone10,4",
"iPhone10,5",
"iPhone10,6",
"iPhone11,2",
"iPhone11,4",
"iPhone11,6",
"iPhone11,8",
"iPad4,1",
"iPad4,2",
"iPad4,3",
"iPad4,4",
"iPad4,5",
"iPad4,6",
"iPad4,7",
"iPad4,8",
"iPad4,9",
"iPad5,1",
"iPad5,2",
"iPad5,3",
"iPad5,4",
"iPad6,3",
"iPad6,4",
"iPad6,7",
"iPad6,8",
"iPad6,11",
"iPad6,12",
"iPad7,1",
"iPad7,2",
"iPad7,3",
"iPad7,4",
"iPad7,5",
"iPad7,6",
"iPad8,1",
"iPad8,2",
"iPad8,3",
"iPad8,4",
"iPad8,5",
"iPad8,6",
"iPad8,7",
"iPad8,8",
"iPad11,1",
"iPad11,2",
"iPad11,3",
"iPad11,4",
"iPod7,1",
'

# armv7 Support
export ARMV7_DEVICES=\
'
"iPhone2,1",
"iPhone3,1",
"iPhone3,2",
"iPhone3,3",
"iPhone4,1",
"iPhone5,1",
"iPhone5,2",
"iPhone5,3",
"iPhone5,4",
"iPad1,1",
"iPad1,2",
"iPad2,1",
"iPad2,2",
"iPad2,3",
"iPad2,4",
"iPad2,5",
"iPad2,6",
"iPad2,7",
"iPad3,1",
"iPad3,2",
"iPad3,3",
"iPad3,4",
"iPad3,5",
"iPad3,6",
"iPod3,1",
"iPod4,1",
"iPod5,1",
'


================================================
FILE: RunScript/env.sh
================================================
#!/usr/bin/env zsh --login

# Base Dir
BASEDIR=$(realpath "${PROJECT_DIR}")

# 注入 framework 名称
export FRAMEWORK_NAME="TLocationPlugin"

# App 包名
export APP_NAME="wework"

# 二进制文件名称
export BINARY_NAME="wework"

# Payload Path
export PAYLOAD_PATH="${BASEDIR}/Payload"

# App 包根目录
export APP_CONTENT_PATH="${PAYLOAD_PATH}/${BINARY_NAME}.app"

# 默认 App icon 图片名称
export PRIMARY_ICON_NAME=""


================================================
FILE: RunScript/inject.sh
================================================
#!/usr/bin/env zsh --login

set -ex

CUR_DIR=$(realpath $(dirname "$0"))

source "$CUR_DIR/devices_arm_info.sh"
source "$CUR_DIR/env.sh"


ORIGIN_APP_NAME="${APP_NAME}_origin.ipa"
NEW_APP_NAME="${APP_NAME}_new.ipa"

# clean
rm -rf "$PAYLOAD_PATH"

# unzip & copy Framework
unzip "${ORIGIN_APP_NAME}"
FRAMEWORKS_PATH="${APP_CONTENT_PATH}/Frameworks"
if [ ! -d "${FRAMEWORKS_PATH}" ]; then
    mkdir -p "${FRAMEWORKS_PATH}"
fi
cp -rf "${FRAMEWORK_NAME}.framework" "${FRAMEWORKS_PATH}"

# inject
pushd . > /dev/null

cd "${APP_CONTENT_PATH}"

# 修改支持的机型
#BINARY_INFO=`file ${BINARY_NAME}`
#SUPPORTED_DEVICE_LIST=""
#echo $ARM64_DEVICES
#echo $ARMV7_DEVICES
#
#if [[ "${BINARY_INFO}" =~ "arm64" ]]; then
#    SUPPORTED_DEVICE_LIST="${SUPPORTED_DEVICE_LIST}${ARM64_DEVICES}"
#fi
#
#if [[ "${BINARY_INFO}" =~ "armv7" ]]; then
#    SUPPORTED_DEVICE_LIST="${SUPPORTED_DEVICE_LIST}${ARMV7_DEVICES}"
#fi

PLIST_FILE_PATH="${APP_CONTENT_PATH}/Info.plist"
plutil -remove UISupportedDevices Info.plist
#plutil -replace UISupportedDevices -json "[${SUPPORTED_DEVICE_LIST}]" "${PLIST_FILE_PATH}"
#plutil -p "${PLIST_FILE_PATH}"

# 注入动态库
yololib "${BINARY_NAME}" "Frameworks/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# 注入图标
python3 "${CUR_DIR}/inject_app_icon.py"

popd > /dev/null


# clean
rm -f "${NEW_APP_NAME}"

# zip
zip -r "${NEW_APP_NAME}" ./Payload

# clean
rm -rf "$PAYLOAD_PATH"

set +ex

# sign
echo "new app: ${NEW_APP_NAME}; \nyou should sign it, recommend fastlane"

fastlane sigh resign -i "your_dev_cert" -p "your_mobileprovision_file" ${NEW_APP_NAME}.ipa



================================================
FILE: RunScript/inject_app_icon.py
================================================
# /usr/local/bin/python3
# -*- coding: utf-8 -*-

import os
import sys
import glob
import shutil
import pprint

from PIL import Image

iPhone = True
iPad = False

if sys.version_info < (3, 4):
    import biplist
    def read_plist(path):
        return biplist.readPlist(path)

    def write_plist(info, path):
        biplist.writePlist(info, path, binary=False)

else:
    import plistlib
    def read_plist(path):
        with open(path, 'rb') as f:
            return plistlib.load(f)

    def write_plist(info, path):
        with open(path, 'wb') as fp:
            plistlib.dump(info, fp)

src_root = os.path.dirname(os.path.realpath(__file__))
input_dir = os.path.join(src_root, "logos")
output_dir = os.path.join(src_root, "icons")

iPhone_size_scall = [
    (20, 2),
    (20, 3),
    (29, 2),
    (29, 3),
    (40, 2),
    (40, 3),
    (60, 2),
    (60, 3),
]

iPad_size_scall = [
    (20, 1),
    (20, 2),
    (29, 1),
    (29, 2),
    (40, 1),
    (40, 2),
    (76, 1),
    (76, 2),
    (83.5, 2),
]


def convertImage(imageFile, outdir, size, scale, is_iPhone):
    image = Image.open(imageFile)
    try:
        basename = os.path.basename(imageFile)
        name = os.path.splitext(basename)[0]
        scale_string = "" if scale == 1 else "@%dx" % scale
        suffix = "" if is_iPhone else "~ipad"
        new_name = "{name}{size}x{size}{scale_string}{suffix}.png".format(
            name=name,
            size=size,
            scale_string=scale_string,
            suffix=suffix,
        )
        size_of_scale = int(size*scale)
        resize = (size_of_scale, size_of_scale)
        new_image = image.resize(resize, Image.BILINEAR)
        new_image.save(os.path.join(output_dir, new_name))
    except Exception as e:
        print(e)


def createCFBundleIconFiles(name, is_iPhone):
    CFBundleIconFiles = set()
    size_scale_array = iPhone_size_scall if is_iPhone else iPad_size_scall
    for (size, scale) in size_scale_array:
        file_name = "{name}{size}x{size}".format(
            name=name,
            size=size,
        )
        CFBundleIconFiles.add(file_name)
    CFBundleIconFilesArray = list(CFBundleIconFiles)
    CFBundleIconFilesArray.sort()
    return CFBundleIconFilesArray


def createCFBundleAlternateIconSingle(name, is_iPhone):
    CFBundleIconFiles = createCFBundleIconFiles(name, is_iPhone)
    info_dict = {"UIPrerenderedIcon": False}
    info_dict["CFBundleIconFiles"] = CFBundleIconFiles
    return info_dict


def createPrimaryIconInfo(primaryIconName, is_iPhone):
    CFBundlePrimaryIcon = {}
    CFBundlePrimaryIcon["CFBundleIconName"] = primaryIconName
    CFBundleIconFiles = createCFBundleIconFiles(primaryIconName, is_iPhone)
    CFBundlePrimaryIcon["CFBundleIconFiles"] = CFBundleIconFiles
    return CFBundlePrimaryIcon


def createCFBundleAlternateIcons(names, is_iPhone):
    CFBundleAlternateIcons = {
        "UINewsstandBindingType": "UINewsstandBindingTypeMagazine",
        "UINewsstandBindingEdge": "UINewsstandBindingEdgeLeft",
    }
    for name in names:
        CFBundleAlternateIcons[name] = createCFBundleAlternateIconSingle(name, is_iPhone)
    return CFBundleAlternateIcons


def createNewIconInfo(names, newPrimaryIcon, oldPrimaryInfo, is_iPhone):
    key = "CFBundleIcons" if is_iPhone else "CFBundleIcons~ipad"
    icons = {}
    icons["CFBundleAlternateIcons"] = createCFBundleAlternateIcons(names, is_iPhone)
    if newPrimaryIcon == None or newPrimaryIcon == "":
        if oldPrimaryInfo != None:
            icons["CFBundlePrimaryIcon"] = oldPrimaryInfo
    else:
        icons["CFBundlePrimaryIcon"] = createPrimaryIconInfo(newPrimaryIcon, is_iPhone)

    return icons


def moveIconsToDirectory(origin_dir_path, dest_dir_path):
    imageRe = os.path.join(origin_dir_path, "*.png")
    for imageFile in glob.glob(imageRe):
        basename = os.path.basename(imageFile)
        dest_file_path = os.path.join(dest_dir_path, basename)
        shutil.move(imageFile, dest_file_path)


def setIcon(plist_info, newIconNames, newPrimaryIcon, is_iPhone):
    key = "CFBundleIcons" if is_iPhone else "CFBundleIcons~ipad"
    primaryIconKey = "CFBundlePrimaryIcon"

    if not plist_info.__contains__(key) or not plist_info[key].__contains__(primaryIconKey):
        return
    
    oldPrimaryInfo = plist_info[key][primaryIconKey]
    newIconInfo = createNewIconInfo(newIconNames, newPrimaryIcon, oldPrimaryInfo, is_iPhone)
    plist_info[key] = newIconInfo



if __name__ == '__main__':
    """Create Dir"""
    if os.path.exists(output_dir):
        if os.path.isfile(output_dir):
            os.remove(output_dir)
        elif os.path.isdir(output_dir):
            shutil.rmtree(output_dir, ignore_errors=True)
    os.makedirs(output_dir, exist_ok=False)

    """Convert icons"""
    imageRe = os.path.join(input_dir, "*.png")
    iconNames = []
    for imageFile in glob.glob(imageRe):
        basename = os.path.basename(imageFile)
        name = os.path.splitext(basename)[0]
        iconNames.append(name)
        for (size, scale) in iPhone_size_scall:
            convertImage(imageFile, output_dir, size, scale, iPhone)
        for (size, scale) in iPad_size_scall:
            convertImage(imageFile, output_dir, size, scale, iPad)


    """Add icons to App"""
    app_content_path = os.getenv("APP_CONTENT_PATH")

    if app_content_path == None:
        raise ValueError("No `APP_CONTENT_PATH` Environment Variable")
    if not os.path.exists(app_content_path):
        raise ValueError("%s not Exists" % app_content_path)

    print("Move App icons: `%s` => `%s`" % (output_dir, app_content_path))
    moveIconsToDirectory(output_dir, app_content_path)
    print("Add App Icon Success")

    """Edit Info.plist"""
    primaryIconName = os.getenv("PRIMARY_ICON_NAME")
    plistFilePath = os.path.join(app_content_path, "Info.plist")

    if not os.path.exists(plistFilePath):
        raise ValueError("%s not Exists" % plistFilePath)

    print("Edit Info.plist: ", plistFilePath)
    plistInfo = read_plist(plistFilePath)


    """set icons"""
    setIcon(plistInfo, iconNames, primaryIconName, iPhone)
    setIcon(plistInfo, iconNames, primaryIconName, iPad)

    os.remove(plistFilePath)
    write_plist(plistInfo, plistFilePath)

    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(plistInfo)

    print("Edit Info.plist Success")


================================================
FILE: TLocationPlugin/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleVersion</key>
	<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>


================================================
FILE: TLocationPlugin/NSObject+TLocationPlugin.h
================================================
//
//  NSObject+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN

@interface NSObject (TLocationPlugin)

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/NSObject+TLocationPlugin.m
================================================
//
//  NSObject+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <CoreLocation/CoreLocation.h>
#import "NSObject+TLocationPlugin.h"
#import "TSafeRuntimeCFunc.h"
#import "TLocationManager.h"
#import "UIWindow+TLocationPluginToast.h"
#import <objc/runtime.h>
#import <dlfcn.h>

@implementation NSObject (TLocationPlugin)

+ (void)load {
    // Selector Name
    const char *old_location_sel_name = sel_getName(@selector(locationManager:didUpdateToLocation:fromLocation:));
    const char *new_location_sel_name = sel_getName(@selector(locationManager:didUpdateLocations:));
    
    /// 替换所有方法
    int all_classes_count;
    Class *all_classes = NULL;
    all_classes_count = objc_getClassList(NULL, 0);
    if (all_classes_count > 0 ) {
        all_classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * all_classes_count);
        objc_getClassList(all_classes, all_classes_count);
        for (int i = 0; i < all_classes_count; i++) {
            Class cls = all_classes[i];
            unsigned int methods_count;
            Method *methods = class_copyMethodList(cls, &methods_count);
            for (int i = 0; i < methods_count; i++) {
                const char *selName = sel_getName(method_getName(methods[i]));
                // 是定位函数
                if (strcmp(selName, old_location_sel_name) == 0 ||
                    strcmp(selName, new_location_sel_name) == 0) {
                    [self replaceCLLocationsFunctionToClass:cls];
                    break;
                }
            }
            free(methods);
        }
        free(all_classes);
    }
}

+ (void)replaceCLLocationsFunctionToClass:(Class)cls {
    if ([cls instancesRespondToSelector:@selector(locationManager:didUpdateToLocation:fromLocation:)]) {
        t_exchange_instance_method(cls,
                                   @selector(locationManager:didUpdateToLocation:fromLocation:),
                                   @selector(__t_locationManager:didUpdateToLocation:fromLocation:));
    }
    
    if ([cls instancesRespondToSelector:@selector(locationManager:didUpdateLocations:)]) {
        t_exchange_instance_method(cls,
                                   @selector(locationManager:didUpdateLocations:),
                                   @selector(__t_locationManager:didUpdateLocations:));
    }
}

- (void)__t_locationManager:(CLLocationManager *)manager
        didUpdateToLocation:(CLLocation *)newLocation
               fromLocation:(CLLocation *)oldLocation API_AVAILABLE(macos(10.6)) {
    BOOL useHook = TLocationManager.shared.usingHookLocation && TLocationManager.shared.hasCachedLocation;
    // 不使用或者暂时暂停使用,调用原方法
    if (!useHook || TLocationManager.shared.isSuspend) {
        [self t_showTostForCLLocation:newLocation];
        [self __t_locationManager:manager didUpdateToLocation:newLocation fromLocation:oldLocation];
        return;
    }
    
    /// CLLocation 使用WGS84坐标
    CLLocation *t_newLocation = [[CLLocation alloc] initWithCoordinate:TLocationManager.shared.randomWGS84Coordinate
                                                              altitude:newLocation.altitude
                                                    horizontalAccuracy:newLocation.horizontalAccuracy
                                                      verticalAccuracy:newLocation.verticalAccuracy
                                                                course:newLocation.course
                                                                 speed:newLocation.speed
                                                             timestamp:newLocation.timestamp];
    
    [self t_showTostForCLLocation:t_newLocation];
    [self __t_locationManager:manager didUpdateToLocation:t_newLocation fromLocation:oldLocation];
}

- (void)__t_locationManager:(CLLocationManager *)manager
         didUpdateLocations:(NSArray<CLLocation *> *)locations {
    BOOL useHook = TLocationManager.shared.usingHookLocation && TLocationManager.shared.hasCachedLocation;
    // 不使用或者暂时暂停使用,调用原方法
    if (!useHook || TLocationManager.shared.isSuspend) {
        [self t_showTostForCLLocations:locations];
        [self __t_locationManager:manager didUpdateLocations:locations];
        return;
    }
    
    NSMutableArray<CLLocation *> *t_locations = [NSMutableArray<CLLocation *> array];
    for (CLLocation *location in locations) {
        /// CLLocation 使用WGS84坐标
        CLLocation *t_location = [[CLLocation alloc] initWithCoordinate:TLocationManager.shared.randomWGS84Coordinate
                                                               altitude:location.altitude
                                                     horizontalAccuracy:location.horizontalAccuracy
                                                       verticalAccuracy:location.verticalAccuracy
                                                                 course:location.course
                                                                  speed:location.speed
                                                              timestamp:location.timestamp];
        [t_locations addObject:t_location];
    }
    
    [self t_showTostForCLLocations:t_locations];
    [self __t_locationManager:manager didUpdateLocations:t_locations];
}

- (void)t_showTostForCLLocations:(NSArray<CLLocation *> *)locations {
    if (TLocationManager.shared.usingToast) {
        [UIWindow t_showTostForCLLocations:locations];
    }
}

- (void)t_showTostForCLLocation:(CLLocation *)location {
    if (TLocationManager.shared.usingToast) {
        [UIWindow t_showTostForCLLocation:location];
    }
}

@end



================================================
FILE: TLocationPlugin/Others/TLocationManager.h
================================================
//
//  TLocationManager.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import "TLocationModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface TLocationManager : NSObject

@property (class, nonatomic, assign, readonly) TLocationManager *shared;

/// 是否暂时暂停 HOOK(库内使用)
@property (nonatomic, assign, getter=isSuspend) BOOL suspend;

/// 当前使用的名称
@property (nonatomic, copy  ) NSString *locationName;
/// 当前使用的纬度
@property (nonatomic, assign) CLLocationDegrees latitude;
/// 当前使用的经度
@property (nonatomic, assign) CLLocationDegrees longitude;
/// 扩散范围, 默认为 10
@property (nonatomic, assign) NSInteger range;
/// 是否使用
@property (nonatomic, assign) BOOL usingHookLocation;
/// 是否开启 toast 提示
@property (nonatomic, assign) BOOL usingToast;

/// 缓存的所有位置数据, setter 方法不自动保存, 保存调用 `- saveCacheDataArray`
@property (nonatomic, copy, nullable) NSArray<TLocationModel *> *cacheDataArray;

@property (nonatomic, assign, readonly) NSUInteger cacheDataArrayHash;

/// 是否有缓存数据, 都为 0 判断为无数据
@property (nonatomic, assign, readonly) BOOL hasCachedLocation;
/// 取随机纬度 (根据当前纬度以及扩散范围生成)
@property (nonatomic, assign, readonly) CLLocationDegrees randomLatitude;
/// 取随机经度 (根据当前经度以及扩散范围生成)
@property (nonatomic, assign, readonly) CLLocationDegrees randomLongitude;
/// 取随机坐标国测局编码 (根据当前经度,纬度以及扩散范围生成)
@property (nonatomic, assign, readonly) CLLocationCoordinate2D randomGCJ02Coordinate;
/// 取随机坐标 (根据当前经度,纬度以及扩散范围生成)
@property (nonatomic, assign, readonly) CLLocationCoordinate2D randomWGS84Coordinate;

- (void)saveCacheDataArray;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Others/TLocationManager.m
================================================
//
//  TLocationManager.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationManager.h"
#import "TLocationPluginLocationConverter.h"

@implementation TLocationManager {
    NSString                    *_locationName;
    CLLocationDegrees           _latitude;
    CLLocationDegrees           _longitude;
    NSInteger                   _range;
    BOOL                        _usingHookLocation;
    BOOL                        _usingToast;
    NSArray<TLocationModel *>   * _cacheDataArray;
}

@synthesize locationName        = _locationName;
@synthesize latitude            = _latitude;
@synthesize longitude           = _longitude;
@synthesize range               = _range;
@synthesize usingHookLocation   = _usingHookLocation;
@synthesize usingToast          = _usingToast;
@synthesize cacheDataArray      = _cacheDataArray;


#pragma mark - Singletion
#pragma mark -

static TLocationManager *_instance;
+ (TLocationManager *)shared {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
#if __has_feature(objc_arc)
        _instance = [[self alloc] init];
        NSString *path = _instance.cacheDataArrayArchivePath;
        if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
            _instance->_cacheDataArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        }
#else
        _instance = [[[self alloc] init] autorelease];
#endif
    });
    return _instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

- (instancetype)init {
    self = [super init];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (self) {}
    });
    return self;
}

- (instancetype)copyWithZone:(NSZone *)zone {
    return _instance;
}

- (instancetype)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}

#if !__has_feature(objc_arc)
- (instancetype)retain { return self; }
- (NSUInteger)retainCount { return NSUIntegerMax; }
- (oneway void)release {}
- (instancetype)autorelease{ return self; }
#endif

#pragma mark - locationName
static NSString * const _t_locationNameKey = @"_T_CacheKeyTypeLocationName";
- (NSString *)locationName {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_locationName = [[NSUserDefaults standardUserDefaults] stringForKey:_t_locationNameKey];
    });
    return self->_locationName;
}
- (void)setLocationName:(NSString *)locationName {
    self->_locationName = locationName;
    [[NSUserDefaults standardUserDefaults] setObject:locationName forKey:_t_locationNameKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - latitude
static NSString * const _t_latitudeKey = @"_T_CacheKeyTypeLatitude";
- (CLLocationDegrees)latitude {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_latitude = [[NSUserDefaults standardUserDefaults] doubleForKey:_t_latitudeKey];
    });
    return self->_latitude;
}
- (void)setLatitude:(CLLocationDegrees)latitude {
    self->_latitude = latitude;
    [[NSUserDefaults standardUserDefaults] setDouble:latitude forKey:_t_latitudeKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - longitude
static NSString * const _t_longitudeKey = @"_T_CacheKeyTypeLongitude";
- (CLLocationDegrees)longitude {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_longitude = [[NSUserDefaults standardUserDefaults] doubleForKey:_t_longitudeKey];
    });
    return self->_longitude;
}
- (void)setLongitude:(CLLocationDegrees)longitude {
    self->_longitude = longitude;
    [[NSUserDefaults standardUserDefaults] setDouble:longitude forKey:_t_longitudeKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - range
static NSString * const _t_rangeKey = @"_T_CacheKeyTypeRange";
- (NSInteger)range {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_range = [[NSUserDefaults standardUserDefaults] integerForKey:_t_rangeKey];
        if (self->_range <= 0) {
            self->_range = 10;
        }
    });
    
    return self->_range;
}
- (void)setRange:(NSInteger)range {
    self->_range = range;
    if (self->_range <= 0) {
        self->_range = 10;
    }
    [[NSUserDefaults standardUserDefaults] setInteger:self->_range forKey:_t_rangeKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}


#pragma mark - usingHookLocation
static NSString * const _t_usingHookLocationKey = @"_T_CacheKeyTypeUsingHookLocation";
- (BOOL)usingHookLocation {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_usingHookLocation = [[NSUserDefaults standardUserDefaults] boolForKey:_t_usingHookLocationKey];
    });
    return self->_usingHookLocation;
}
- (void)setUsingHookLocation:(BOOL)usingHookLocation {
    self->_usingHookLocation = usingHookLocation;
    [[NSUserDefaults standardUserDefaults] setBool:usingHookLocation forKey:_t_usingHookLocationKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - usingToast
static NSString * const _t_usingToastKey = @"_T_CacheKeyTypeUsingToast";
- (BOOL)usingToast {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        self->_usingToast = [[NSUserDefaults standardUserDefaults] boolForKey:_t_usingToastKey];
    });
    return self->_usingToast;
}
- (void)setUsingToast:(BOOL)usingToast {
    self->_usingToast = usingToast;
    [[NSUserDefaults standardUserDefaults] setBool:usingToast forKey:_t_usingToastKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

#pragma mark - cacheDataArray
- (NSString *)cacheDataArrayArchivePath {
    static NSString *_t_cacheDataArrayArchivePath = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSArray<NSString *> *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentDirPath = [paths lastObject];
        _t_cacheDataArrayArchivePath = [documentDirPath stringByAppendingPathComponent:@"_T_CacheKeyTypeDataArray.archiver"];
    });
    return _t_cacheDataArrayArchivePath;
}

- (NSArray<TLocationModel *> *)cacheDataArray {
    return self->_cacheDataArray;
}

- (void)setCacheDataArray:(NSArray<TLocationModel *> *)cacheDataArray {
    self->_cacheDataArray = cacheDataArray;
}

- (NSUInteger)cacheDataArrayHash {
    NSUInteger hash = 0;
    for (TLocationModel *model in self->_cacheDataArray) {
        // 左移确保返回 hash 与顺序相关
        hash = (hash << 1) ^ model.hash;
    }
    return hash;
}

- (void)saveCacheDataArray {
    NSString *path = self.cacheDataArrayArchivePath;
    if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    }
    if (self->_cacheDataArray != nil) {
        [NSKeyedArchiver archiveRootObject:self->_cacheDataArray toFile:self.cacheDataArrayArchivePath];
    }
}

- (BOOL)hasCachedLocation {
    return self.longitude != 0 && self.latitude != 0;
}

#pragma mark - Random Values
- (CLLocationDegrees)randomLatitude {
    return [self rangeDegressForDegrees:self.latitude];
}

- (CLLocationDegrees)randomLongitude {
    return [self rangeDegressForDegrees:self.longitude];
}

- (CLLocationCoordinate2D)randomGCJ02CoordinateCoordinate {
    /// 地图点击的坐标默认就是国测局坐标
    return CLLocationCoordinate2DMake(self.randomLatitude, self.randomLongitude);
}

- (CLLocationCoordinate2D)randomWGS84Coordinate {
    return [TLocationPluginLocationConverter gcj02ToWgs84:self.randomGCJ02CoordinateCoordinate];
}


/// 取 15/16 位有效数字
- (CLLocationDegrees)rangeDegressForDegrees:(CLLocationDegrees)degrees {
    NSInteger randomRange = arc4random() % self.range;
    
    /// 从小数点后第五位开始加/减 randomRange
    CLLocationDegrees randomDegrees = randomRange * 0.00001;
    CLLocationDegrees newDegrees;
    
    /// 随机加减
    if (arc4random() % 2 == 0) {
        newDegrees = degrees + randomDegrees;
    } else {
        newDegrees = degrees - randomDegrees;
    }
    
    /// 转换为 String 处理
    NSString *newDegreesString = @(newDegrees).stringValue;
    NSRange decimalPointRange = [newDegreesString rangeOfString:@"."];
    if (decimalPointRange.location == NSNotFound) {
        newDegreesString = [newDegreesString stringByAppendingString:@"."];
    } else {
        /// + 后 5 位
        NSUInteger toIndex = decimalPointRange.location + decimalPointRange.length + 5;
        if (toIndex <= newDegreesString.length) {
            newDegreesString = [newDegreesString substringToIndex:toIndex];
        } else {
            /// 不进行截取操作
            /// 但是应该不可能到这里吧, 除非数据本来长度就很小而且 randomRange 是 10 的倍数
        }
    }
    
    /// 去除首尾 `空格`
    static NSCharacterSet *trimmingSet = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        trimmingSet = [NSCharacterSet characterSetWithCharactersInString:@" "];
    });
    [newDegreesString stringByTrimmingCharactersInSet:trimmingSet];
    /// 16 位有效数字 + 1 位小数点 + (负号 ? 1 : 0)
    NSUInteger toLenght = 16 + 1 + ([newDegreesString hasPrefix:@"-"] ? 1 : 0);
    while (newDegreesString.length < toLenght) {
        newDegreesString = [newDegreesString stringByAppendingFormat:@"%d", arc4random() % 10];
    };
    
    /// 转换为 double (CLLocationDegrees)
    newDegrees = newDegreesString.doubleValue;
    
    return newDegrees;
}

@end


================================================
FILE: TLocationPlugin/Others/TLocationModel.h
================================================
//
//  TLocationModel.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

NS_ASSUME_NONNULL_BEGIN

@interface TLocationModel : NSObject <NSCoding, NSCopying>

/// 名称
@property (nonatomic, copy) NSString *name;

/// 纬度
@property (nonatomic, assign) CLLocationDegrees latitude;

/// 经度
@property (nonatomic, assign) CLLocationDegrees longitude;

/// 是否是当前选择的数据
@property (nonatomic, assign) BOOL isSelect;

+ (instancetype)modelWithName:(NSString *)name
                     latitude:(CLLocationDegrees)latitude
                    longitude:(CLLocationDegrees)longitude;

+ (instancetype)modelWithSubLocality:(nullable NSString *)subLocality
                                name:(NSString *)name
                            latitude:(CLLocationDegrees)latitude
                           longitude:(CLLocationDegrees)longitude;

- (NSString *)locationText;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Others/TLocationModel.m
================================================
//
//  TLocationModel.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationModel.h"

@implementation TLocationModel

- (NSUInteger)hash {
    return self.name.hash ^ @(self.latitude).hash ^ @(self.longitude).hash ^ @(self.isSelect).hash;
}

+ (instancetype)modelWithName:(NSString *)name
                     latitude:(CLLocationDegrees)latitude
                    longitude:(CLLocationDegrees)longitude {
    return [self modelWithSubLocality:nil
                                 name:name
                             latitude:latitude
                            longitude:longitude];
}

+ (instancetype)modelWithSubLocality:(nullable NSString *)subLocality
                                name:(NSString *)name
                            latitude:(CLLocationDegrees)latitude
                           longitude:(CLLocationDegrees)longitude {
    return [[self alloc] initWithSubLocality:subLocality
                                        name:name
                                    latitude:latitude
                                   longitude:longitude];
}

- (instancetype)initWithSubLocality:(nullable NSString *)subLocality
                               name:(NSString *)name
                           latitude:(CLLocationDegrees)latitude
                          longitude:(CLLocationDegrees)longitude {
    self = [super init];
    if (self) {
        if (subLocality) {
            self.name = [NSString stringWithFormat:@"%@ %@", subLocality, name];
        } else {
            self.name = name;
        }
        self.latitude = latitude;
        self.longitude = longitude;
    }
    return self;
}

- (NSString *)locationText {
    return [NSString stringWithFormat:@"纬度: %@\n经度: %@", @(self.latitude).stringValue, @(self.longitude).stringValue];
}

- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeDouble:self.latitude forKey:@"latitude"];
    [aCoder encodeDouble:self.longitude forKey:@"longitude"];
    [aCoder encodeBool:self.isSelect forKey:@"isSelect"];
}

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.latitude = [aDecoder decodeDoubleForKey:@"latitude"];
        self.longitude = [aDecoder decodeDoubleForKey:@"longitude"];
        self.isSelect = [aDecoder decodeBoolForKey:@"isSelect"];
    }
    return self;
}

- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    TLocationModel *model = [[self.class allocWithZone:zone] init];
    model.name = self.name;
    model.latitude = self.latitude;
    model.longitude = self.longitude;
    return model;
}

@end


================================================
FILE: TLocationPlugin/Others/TLocationPluginLocationConverter.h
================================================
//
//  JZLocationConverter.h
//  JZCLLocationMangerDome
//
//  Created by jack zhou on 13-8-22.
//  Copyright (c) 2013年 JZ. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

NS_ASSUME_NONNULL_BEGIN

/// 防止重名, 定义为 TLocationPluginLocationConverter
@interface TLocationPluginLocationConverter : NSObject


/// 世界标准地理坐标(WGS-84) 转换成 中国国测局地理坐标 (GCJ-02) <火星坐标>
/// @param location 世界标准地理坐标(WGS-84)
/// @return 中国国测局地理坐标 (GCJ-02) <火星坐标>
+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location;


/// 中国国测局地理坐标 (GCJ-02) 转换成 世界标准地理坐标 (WGS-84)
/// 此接口有1-2米左右的误差,需要精确定位情景慎用
/// @param location 中国国测局地理坐标 (GCJ-02)
/// @return 世界标准地理坐标 (WGS-84)
+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location;


/// 世界标准地理坐标(WGS-84) 转换成 百度地理坐标 (BD-09)
/// @param location 世界标准地理坐标(WGS-84)
/// @return 百度地理坐标 (BD-09)
+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location;


/// 中国国测局地理坐标 (GCJ-02) <火星坐标> 转换成 百度地理坐标 (BD-09)
/// @param location 中国国测局地理坐标 (GCJ-02) <火星坐标>
/// @return 百度地理坐标 (BD-09)
+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location;


/// 百度地理坐标 (BD-09) 转换成 中国国测局地理坐标 (GCJ-02) <火星坐标>
/// @param location 百度地理坐标 (BD-09)
/// @return 中国国测局地理坐标 (GCJ-02) <火星坐标>
+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location;


/// 百度地理坐标 (BD-09) 转换成 世界标准地理坐标 (WGS-84)
/// @param location 百度地理坐标 (BD-09)
/// @return 世界标准地理坐标 (WGS-84)
+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location;

@end


NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Others/TLocationPluginLocationConverter.m
================================================
//
//  JZLocationConverter.m
//  JZCLLocationMangerDome
//
//  Created by jack zhou on 13-8-22.
//  Copyright (c) 2013年 JZ. All rights reserved.
//

#import "TLocationPluginLocationConverter.h"
#import <CoreLocation/CoreLocation.h>

#define LAT_OFFSET_0(x,y) -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x))
#define LAT_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_2 (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0
#define LAT_OFFSET_3 (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0

#define LON_OFFSET_0(x,y) 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x))
#define LON_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_2 (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0
#define LON_OFFSET_3 (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0

#define RANGE_LON_MAX 137.8347
#define RANGE_LON_MIN 72.004
#define RANGE_LAT_MAX 55.8271
#define RANGE_LAT_MIN 0.8293
// jzA = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;
#define jzA 6378245.0
#define jzEE 0.00669342162296594323

@implementation TLocationPluginLocationConverter

+ (double)transformLat:(double)x bdLon:(double)y {
    double ret = LAT_OFFSET_0(x, y);
    ret += LAT_OFFSET_1;
    ret += LAT_OFFSET_2;
    ret += LAT_OFFSET_3;
    return ret;
}

+ (double)transformLon:(double)x bdLon:(double)y {
    double ret = LON_OFFSET_0(x, y);
    ret += LON_OFFSET_1;
    ret += LON_OFFSET_2;
    ret += LON_OFFSET_3;
    return ret;
}

+ (BOOL)outOfChina:(double)lat bdLon:(double)lon {
    if (lon < RANGE_LON_MIN || lon > RANGE_LON_MAX)
        return true;
    if (lat < RANGE_LAT_MIN || lat > RANGE_LAT_MAX)
        return true;
    return false;
}

+ (CLLocationCoordinate2D)gcj02Encrypt:(double)ggLat bdLon:(double)ggLon {
    CLLocationCoordinate2D resPoint;
    double mgLat;
    double mgLon;
    if ([self outOfChina:ggLat bdLon:ggLon]) {
        resPoint.latitude = ggLat;
        resPoint.longitude = ggLon;
        return resPoint;
    }
    double dLat = [self transformLat:(ggLon - 105.0)bdLon:(ggLat - 35.0)];
    double dLon = [self transformLon:(ggLon - 105.0) bdLon:(ggLat - 35.0)];
    double radLat = ggLat / 180.0 * M_PI;
    double magic = sin(radLat);
    magic = 1 - jzEE * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * M_PI);
    dLon = (dLon * 180.0) / (jzA / sqrtMagic * cos(radLat) * M_PI);
    mgLat = ggLat + dLat;
    mgLon = ggLon + dLon;
    
    resPoint.latitude = mgLat;
    resPoint.longitude = mgLon;
    return resPoint;
}

+ (CLLocationCoordinate2D)gcj02Decrypt:(double)gjLat gjLon:(double)gjLon {
    CLLocationCoordinate2D  gPt = [self gcj02Encrypt:gjLat bdLon:gjLon];
    double dLon = gPt.longitude - gjLon;
    double dLat = gPt.latitude - gjLat;
    CLLocationCoordinate2D pt;
    pt.latitude = gjLat - dLat;
    pt.longitude = gjLon - dLon;
    return pt;
}

+ (CLLocationCoordinate2D)bd09Decrypt:(double)bdLat bdLon:(double)bdLon {
    CLLocationCoordinate2D gcjPt;
    double x = bdLon - 0.0065, y = bdLat - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * M_PI);
    double theta = atan2(y, x) - 0.000003 * cos(x * M_PI);
    gcjPt.longitude = z * cos(theta);
    gcjPt.latitude = z * sin(theta);
    return gcjPt;
}

+(CLLocationCoordinate2D)bd09Encrypt:(double)ggLat bdLon:(double)ggLon {
    CLLocationCoordinate2D bdPt;
    double x = ggLon, y = ggLat;
    double z = sqrt(x * x + y * y) + 0.00002 * sin(y * M_PI);
    double theta = atan2(y, x) + 0.000003 * cos(x * M_PI);
    bdPt.longitude = z * cos(theta) + 0.0065;
    bdPt.latitude = z * sin(theta) + 0.006;
    return bdPt;
}


+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location {
    return [self gcj02Encrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location {
    return [self gcj02Decrypt:location.latitude gjLon:location.longitude];
}


+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location {
    CLLocationCoordinate2D gcj02Pt = [self gcj02Encrypt:location.latitude
                                                  bdLon:location.longitude];
    return [self bd09Encrypt:gcj02Pt.latitude bdLon:gcj02Pt.longitude] ;
}

+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location {
    return  [self bd09Encrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location {
    return [self bd09Decrypt:location.latitude bdLon:location.longitude];
}

+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location {
    CLLocationCoordinate2D gcj02 = [self bd09ToGcj02:location];
    return [self gcj02Decrypt:gcj02.latitude gjLon:gcj02.longitude];
}

@end


================================================
FILE: TLocationPlugin/TLocationPlugin.h
================================================
//
//  TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <Foundation/Foundation.h>

//! Project version number for TLocationPlugin.
FOUNDATION_EXPORT double TLocationPluginVersionNumber;

//! Project version string for TLocationPlugin.
FOUNDATION_EXPORT const unsigned char TLocationPluginVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <TLocationPlugin/PublicHeader.h>


================================================
FILE: TLocationPlugin/TSafeRuntimeCFunc.h
================================================
//
//  TSafeRuntimeCFunc.h
//  TLocationPlugin
//
//  Created by TBD on 2018/4/19.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

#ifdef __cplusplus
extern "C" {
#endif

void t_add_instance_method(Class cls,
                           SEL sel);

void t_add_class_method(Class cls,
                        SEL sel);

/// 先添加 后替换, 防止父类函数指针重复替换
void t_exchange_instance_method(Class cls,
                                SEL originalSel,
                                SEL swizzledSel);
/// 先添加 后替换, 防止父类函数指针重复替换
void t_exchange_class_method(Class cls,
                             SEL originalSel,
                             SEL swizzledSel);

#ifdef __cplusplus
} // extern "C"
#endif

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/TSafeRuntimeCFunc.m
================================================
//
//  TSafeRuntimeCFunc.h
//  TLocationPlugin
//
//  Created by TBD on 2018/4/19.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TSafeRuntimeCFunc.h"
#import <objc/runtime.h>

#ifdef __cplusplus
extern "C" {
#endif
    
    void t_add_instance_method(Class cls, SEL sel) {
        Method method = class_getInstanceMethod(cls, sel);
        class_addMethod(cls,
                        sel,
                        method_getImplementation(method),
                        method_getTypeEncoding(method));
    }
    
    void t_add_class_method(Class cls, SEL sel) {
        Method method = class_getClassMethod(cls, sel);
        class_addMethod(objc_getMetaClass(object_getClassName(cls)),
                        sel,
                        method_getImplementation(method),
                        method_getTypeEncoding(method));
    }
    
    void t_exchange_instance_method(Class cls, SEL sel1, SEL sel2) {
        Method method1 = class_getInstanceMethod(cls, sel1);
        Method method2 = class_getInstanceMethod(cls, sel2);
        if (method1 == NULL || method2 == NULL) {
            NSLog(@"class: %@, no method for sel1: %@, or sel2: %@", cls, NSStringFromSelector(sel1), NSStringFromSelector(sel2));
        }
        
        IMP imp1 = method_getImplementation(method1);
        IMP imp2 = method_getImplementation(method2);
        
        const char *encode1 = method_getTypeEncoding(method1);
        const char *encode2 = method_getTypeEncoding(method2);
        if (strcmp(encode1, encode2) != 0) {
            NSLog(@"type encoding not same for: %@, sel1: %@, sel2: %@", cls, NSStringFromSelector(sel1), NSStringFromSelector(sel2));
            NSLog(@"sel1 type encoding: %s", encode1);
            NSLog(@"sel2 type encoding: %s", encode2);
        }
        
        // 交换实现进行添加函数
        class_replaceMethod(cls, sel1, imp2, encode2);
        class_replaceMethod(cls, sel2, imp1, encode1);
    }
    
    void t_exchange_class_method(Class cls, SEL sel1, SEL sel2) {
        t_exchange_instance_method(object_getClass(cls), sel1, sel2);
    }
    
#ifdef __cplusplus
} // extern "C"
#endif




================================================
FILE: TLocationPlugin/Tools/CALayer+TLocationPlugin.h
================================================
//
//  CALayer+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/6.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface CALayer (TLocationPlugin)

@property (nonatomic, strong, nullable) UIColor *t_borderUIColor;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/CALayer+TLocationPlugin.m
================================================
//
//  CALayer+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/6.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "CALayer+TLocationPlugin.h"

@implementation CALayer (TLocationPlugin)

- (UIColor *)t_borderUIColor {
    return [UIColor colorWithCGColor:self.borderColor];
}

- (void)setT_borderUIColor:(UIColor *)t_borderUIColor {
    self.borderColor = t_borderUIColor.CGColor;
}

@end


================================================
FILE: TLocationPlugin/Tools/NSBundle+TLocationPlugin.h
================================================
//
//  NSBundle+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSBundle (TLocationPlugin)

+ (instancetype)t_bundle;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/NSBundle+TLocationPlugin.m
================================================
//
//  NSBundle+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "NSBundle+TLocationPlugin.h"

@interface __TLocationPlugin_Temp_Bundle_Class : NSObject
@end
@implementation __TLocationPlugin_Temp_Bundle_Class
@end

@implementation NSBundle (TLocationPlugin)

+ (instancetype)t_bundle {
    static NSBundle *_t_bundle = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _t_bundle = [NSBundle bundleForClass:[__TLocationPlugin_Temp_Bundle_Class class]];
        if (_t_bundle == nil) {
            _t_bundle = [NSBundle bundleWithPath:[NSBundle.mainBundle pathForResource:@"Frameworks/TLocationPlugin.framework" ofType:nil]];
        }
    });
    return _t_bundle;
}

@end


================================================
FILE: TLocationPlugin/Tools/TAlertController.h
================================================
//
//  TAlertController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/6.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@class TAlertController;
typedef void(^TAlertControllerBlock)(TAlertController *alert, UIAlertAction *action);

@interface TAlertController: UIAlertController

/// 一个取消按钮
+ (instancetype)singleActionAlertWithTitle:(nullable NSString *)title
                                   message:(nullable NSString *)message
                               actionTitle:(nullable NSString *)actionTitle
                               actionBlock:(nullable TAlertControllerBlock)actionBlock;


/// confirmTitle 在左, cancelTitle 在右
+ (instancetype)confirmAlertWithTitle:(nullable NSString *)title
                              message:(nullable NSString *)message
                          cancelTitle:(nullable NSString *)cancelTitle
                          cancelBlock:(nullable TAlertControllerBlock)cancelBlock
                         confirmTitle:(nullable NSString *)confirmTitle
                         confirmBlock:(nullable TAlertControllerBlock)confirmBlock;

/// destructiveTitle 在左, cancelTitle 在右
+ (instancetype)destructiveAlertWithTitle:(nullable NSString *)title
                                  message:(nullable NSString *)message
                              cancelTitle:(nullable NSString *)cancelTitle
                              cancelBlock:(nullable TAlertControllerBlock)cancelBlock
                         destructiveTitle:(nullable NSString *)destructiveTitle
                         destructiveBlock:(nullable TAlertControllerBlock)destructiveBlock;

/// 编辑框
+ (instancetype)editAlertWithTitle:(nullable NSString *)title
                           message:(nullable NSString *)message
                        labelTexts:(nullable NSArray<NSString *> *)labelTexts
                     defaultValues:(nullable NSArray<NSString *> *)defaultValues
                       cancelTitle:(nullable NSString *)cancelTitle
                       cancelBlock:(nullable TAlertControllerBlock)cancelBlock
                      confirmTitle:(nullable NSString *)confirmTitle
                      confirmBlock:(nullable TAlertControllerBlock)confirmBlock;
/// 翻转 Actions 顺序
- (void)reverseActions;
/// 添加 Action
- (void)addAction:(UIAlertAction *)action;
/// 删除 Action
- (void)removeAction:(UIAlertAction *)action;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/TAlertController.m
================================================
//
//  TAlertController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/6.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TAlertController.h"
#import "TLocationDefine.h"

@interface TAlertController () <UITextFieldDelegate>

@property (nonatomic, assign) BOOL isLoaded;
@property (nonatomic, strong)  UIAlertAction *confirmAction;
@property (nonatomic, copy)  TAlertControllerBlock confirmBlock;
@property (nonatomic, strong) NSMutableArray<UIAlertAction *> *mutableActions;

@end

@implementation TAlertController

#pragma mark - 构造方法
+ (instancetype)alertWithTitle:(NSString *)title
                       message:(NSString *)message
                  confirmTitle:(NSString *)confirmTitle
                  confirmBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))confirmBlock
                   cancelTitle:(NSString *)cancelTitle
                   cancelBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))cancelBlock
                 isDestructive:(BOOL)isDestructive {
    TAlertController *alert = [self alertControllerWithTitle:title
                                                     message:message
                                              preferredStyle:UIAlertControllerStyleAlert];
    @weakify(alert);
    alert.view.tintColor = UIColor.blackColor;
    UIAlertAction *confirmAction = nil;
    UIAlertAction *cancelAction = nil;
    
    if (confirmTitle || confirmBlock) {
        confirmAction = [UIAlertAction actionWithTitle:confirmTitle ?: @"确定"
                                                 style:isDestructive ? UIAlertActionStyleDestructive : UIAlertActionStyleDefault
                                               handler:^(UIAlertAction * _Nonnull action) {
            @strongify(alert);
            if (confirmBlock) {
                confirmBlock(alert, action);
            }
        }];
        alert.confirmAction = confirmAction;
        alert.confirmBlock = confirmBlock;
    }
    if (cancelTitle || cancelBlock || confirmAction == nil) {
        cancelAction = [UIAlertAction actionWithTitle:cancelTitle ?: @"取消"
                                                style:UIAlertActionStyleDefault
                                              handler:^(UIAlertAction * _Nonnull action) {
            @strongify(alert);
            if (cancelBlock) {
                cancelBlock(alert, action);
            }
        }];
    }
    
    if (confirmAction) {
        [alert addAction:confirmAction];
    }
    if (cancelAction) {
        [alert addAction:cancelAction];
    }
    return alert;
}

+ (instancetype)singleActionAlertWithTitle:(NSString *)title
                                   message:(NSString *)message
                               actionTitle:(NSString *)actionTitle
                               actionBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))actionBlock {
    return [self alertWithTitle:title
                        message:message
                   confirmTitle:actionTitle
                   confirmBlock:actionBlock
                    cancelTitle:nil
                    cancelBlock:nil
                  isDestructive:NO];
}

+ (instancetype)confirmAlertWithTitle:(NSString *)title
                              message:(NSString *)message
                          cancelTitle:(NSString *)cancelTitle
                          cancelBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))cancelBlock
                         confirmTitle:(NSString *)confirmTitle
                         confirmBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))confirmBlock {
    return [self alertWithTitle:title
                        message:message
                   confirmTitle:confirmTitle
                   confirmBlock:confirmBlock
                    cancelTitle:cancelTitle
                    cancelBlock:cancelBlock
                  isDestructive:NO];
}

+ (instancetype)destructiveAlertWithTitle:(NSString *)title
                                  message:(NSString *)message
                              cancelTitle:(NSString *)cancelTitle
                              cancelBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))cancelBlock
                         destructiveTitle:(NSString *)destructiveTitle
                         destructiveBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))destructiveBlock {
    return [self alertWithTitle:title
                        message:message
                   confirmTitle:destructiveTitle
                   confirmBlock:destructiveBlock
                    cancelTitle:cancelTitle
                    cancelBlock:cancelBlock
                  isDestructive:YES];
}

/// 编辑框
+ (instancetype)editAlertWithTitle:(nullable NSString *)title
                           message:(nullable NSString *)message
                        labelTexts:(nullable NSArray<NSString *> *)labelTexts
                     defaultValues:(nullable NSArray<NSString *> *)defaultValues
                       cancelTitle:(nullable NSString *)cancelTitle
                       cancelBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))cancelBlock
                      confirmTitle:(nullable NSString *)confirmTitle
                      confirmBlock:(void (^ __nullable)(TAlertController *alert, UIAlertAction *action))confirmBlock {
    if (labelTexts.count == 0 && defaultValues.count == 0) {
        return [self confirmAlertWithTitle:title
                                   message:message
                               cancelTitle:cancelTitle
                               cancelBlock:cancelBlock
                              confirmTitle:confirmTitle
                              confirmBlock:confirmBlock];
    }
    TAlertController *alert = [TAlertController destructiveAlertWithTitle:title
                                                                  message:message
                                                              cancelTitle:cancelTitle
                                                              cancelBlock:cancelBlock
                                                         destructiveTitle:confirmTitle
                                                         destructiveBlock:confirmBlock];
    [alert reverseActions];
    __block BOOL isNeedLabel = NO;
    [labelTexts enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.length > 0) {
            isNeedLabel = YES;
            *stop = YES;
        }
    }];
    for (NSUInteger index=0; index<MAX(labelTexts.count, defaultValues.count); ++index) {
        @weakify(alert);
        [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            @strongify(alert)
            NSString *text = @"";
            if (index < labelTexts.count) {
                text = labelTexts[index];
            }
            if (isNeedLabel && text.length > 0) {
                UILabel *label = [[UILabel alloc] init];
                label.text = [text stringByAppendingString:@": "];
                label.font = [UIFont systemFontOfSize:14];
                textField.leftView = label;
                textField.leftViewMode = UITextFieldViewModeAlways;
            }
            if (index < defaultValues.count) {
                textField.text = defaultValues[index];
            }
            textField.delegate = alert;
            textField.placeholder = text;
            textField.returnKeyType = UIReturnKeyNext;
        }];
    }
    alert.textFields.lastObject.returnKeyType = UIReturnKeyDone;
    return alert;
}

#pragma mark - Life Cycle
- (void)viewDidLoad {}

- (void)viewWillAppear:(BOOL)animated {
    if (!self.isLoaded) {
        for (UIAlertAction *action in self.mutableActions) {
            [super addAction:action];
        }
        [super viewDidLoad];
    }
    [super viewWillAppear:animated];
}

#pragma mark - mutableActions Getter
- (NSMutableArray<UIAlertAction *> *)mutableActions {
    if (self->_mutableActions == nil) {
        self->_mutableActions = [NSMutableArray<UIAlertAction *> array];
    }
    return self->_mutableActions;
}

#pragma mark - Functions
- (void)reverseActions {
    // self.mutableActions = [self.mutableActions reverseObjectEnumerator].allObjects.mutableCopy;
    NSUInteger count = self.mutableActions.count;
    for (NSUInteger index=0; index<count/2; ++index) {
        [self.mutableActions exchangeObjectAtIndex:index withObjectAtIndex:count-1-index];
    }
}

- (void)addAction:(UIAlertAction *)action {
    [self.mutableActions addObject:action];
}

- (void)removeAction:(UIAlertAction *)action {
    [self.mutableActions removeObject:action];
    if (self.confirmAction == action) {
        self.confirmAction = nil;
        self.confirmBlock = nil;
    }
}

#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if (textField == self.textFields.lastObject) {
        if (self.confirmBlock && self.confirmAction) {
            [self.presentingViewController dismissViewControllerAnimated:YES completion:^{
                self.confirmBlock(self, self.confirmAction);
            }];
        }
    }
    return YES;
}


@end


================================================
FILE: TLocationPlugin/Tools/TLocationDefine.h
================================================
//
//  TLocationDefine.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/6.
//  Copyright © 2019 TBD. All rights reserved.
//

#ifndef TLocationDefine_h
#define TLocationDefine_h

#ifndef weakify
#   if DEBUG
#       if __has_feature(objc_arc)
#           define weakify(object) autoreleasepool{} __weak __typeof__(&*object) weak##_##object = object;
#       else
#           define weakify(object) autoreleasepool{} __block __typeof__(&*object) block##_##object = object;
#       endif
#   else
#       if __has_feature(objc_arc)
#           define weakify(object) try{} @finally{} {} __weak __typeof__(&*object) weak##_##object = object;
#       else
#           define weakify(object) try{} @finally{} {} __block __typeof__(&*object) block##_##object = object;
#       endif
#   endif
#endif


#ifndef strongify
#   if DEBUG
#       if __has_feature(objc_arc)
#           define strongify(object) autoreleasepool{} __typeof__(&*object) object = weak##_##object;
#       else
#           define strongify(object) autoreleasepool{} __typeof__(&*object) object = block##_##object;
#       endif
#   else
#       if __has_feature(objc_arc)
#           define strongify(object) try{} @finally{} __typeof__(&*object) object = weak##_##object;
#       else
#           define strongify(object) try{} @finally{} __typeof__(&*object) object = block##_##object;
#       endif
#   endif
#endif


#endif /* TLocationDefine_h */


================================================
FILE: TLocationPlugin/Tools/UIApplication+TLocationPlugin.h
================================================
//
//  UIApplication+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIApplication (TLocationPlugin)

/// 获取 App 的顶层 controller
@property (nonatomic, readonly, nullable) UIViewController *t_topViewController;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UIApplication+TLocationPlugin.m
================================================
//
//  UIApplication+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "UIApplication+TLocationPlugin.h"
#import "UIViewController+TLocationPlugin.h"

@implementation UIApplication (TLocationPlugin)

- (UIViewController *)t_topViewController {
    UIViewController *viewController = self.keyWindow.rootViewController;
    if (viewController) {
        return [UIViewController t_findTopViewControllerFromViewController:viewController];
    }
    return nil;
}

@end


================================================
FILE: TLocationPlugin/Tools/UIImage+TLocationPlugin.h
================================================
//
//  UIImage+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIImage (TLocationPlugin)

+ (nullable instancetype)t_imageNamed:(NSString *)name;

+ (instancetype)t_imageWithColor:(UIColor *)color;
+ (instancetype)t_imageWithColor:(UIColor *)color size:(CGSize)size;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UIImage+TLocationPlugin.m
================================================
//
//  UIImage+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "UIImage+TLocationPlugin.h"
#import "NSBundle+TLocationPlugin.h"

@implementation UIImage (TLocationPlugin)

+ (nullable instancetype)t_imageNamed:(NSString *)name {
    static NSBundle *imageBundle;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        imageBundle = [NSBundle bundleWithPath:[NSBundle.t_bundle pathForResource:@"TLocationPluginImages" ofType:@"bundle"]];
    });
    NSString *imagePath = [imageBundle pathForResource:name ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    return image;
}

+ (instancetype)t_imageWithColor:(UIColor *)color {
    return [self t_imageWithColor:color size:CGSizeMake(1, 1)];
}

+ (instancetype)t_imageWithColor:(UIColor *)color size:(CGSize)size {
    if (!color || size.width <= 0 || size.height <= 0) return nil;
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

@end


================================================
FILE: TLocationPlugin/Tools/UITableView+TLocationPlugin.h
================================================
//
//  UITableView+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UITableView (TLocationPlugin)

@property (nonatomic, assign, getter=isEditBegining) BOOL editBegining;
@property (nonatomic, assign, getter=isEditEnding) BOOL editEnding;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UITableView+TLocationPlugin.m
================================================
//
//  UITableView+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "UITableView+TLocationPlugin.h"
#import "TSafeRuntimeCFunc.h"
#import <objc/runtime.h>

@implementation UITableView (TLocationPlugin)

+ (void)load {
    t_exchange_instance_method(self, @selector(setEditing:), @selector(_t_setEditing:));
    t_exchange_instance_method(self, @selector(setEditing:animated:), @selector(_t_setEditing:animated:));
}

- (BOOL)isEditBegining {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

- (void)setEditBegining:(BOOL)beginingEdit {
    objc_setAssociatedObject(self, @selector(isEditBegining), @(beginingEdit), OBJC_ASSOCIATION_RETAIN);
}


- (BOOL)isEditEnding {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

- (void)setEditEnding:(BOOL)endingEdit {
    objc_setAssociatedObject(self, @selector(isEditEnding), @(endingEdit), OBJC_ASSOCIATION_RETAIN);
}

- (void)_t_setEditing:(BOOL)editing {
    self.editBegining = editing;
    self.editEnding = !editing;
    [self _t_setEditing:editing];
    self.editBegining = NO;
    self.editEnding = NO;
}

- (void)_t_setEditing:(BOOL)editing animated:(BOOL)animated {
    self.editBegining = editing;
    self.editEnding = !editing;
    [self _t_setEditing:editing animated:animated];
    self.editBegining = NO;
    self.editEnding = NO;
}

@end


================================================
FILE: TLocationPlugin/Tools/UIViewController+TLocationPlugin.h
================================================
//
//  UIViewController+TLocationPlugin.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIViewController (TLocationPlugin)

/// 获取当前 viewController 的顶层 controller
@property (nonatomic, readonly) UIViewController *t_topViewController;

/// 获取 viewController 的顶层 controller
+ (UIViewController *)t_findTopViewControllerFromViewController:(UIViewController *)viewController;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UIViewController+TLocationPlugin.m
================================================
//
//  UIViewController+TLocationPlugin.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/8.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "UIViewController+TLocationPlugin.h"

@implementation UIViewController (TLocationPlugin)

- (UIViewController *)t_topViewController {
    return [UIViewController t_findTopViewControllerFromViewController:self];
}

+ (UIViewController *)t_findTopViewControllerFromViewController:(UIViewController *)viewController {
    if ([viewController isKindOfClass:[UISplitViewController class]]) {
        UISplitViewController *svc = (UISplitViewController*)viewController;
        if (svc.viewControllers.count > 0) {
            return [self t_findTopViewControllerFromViewController:svc.viewControllers.lastObject];
        } else {
            return viewController;
        }
    } else if ([viewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *nav = (UINavigationController *)viewController;
        if (nav.viewControllers.count > 0) {
            return [self t_findTopViewControllerFromViewController:nav.topViewController];
        } else {
            return viewController;
        }
    } else if ([viewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController *tbc = (UITabBarController*)viewController;
        if (tbc.viewControllers.count > 0) {
            return [self t_findTopViewControllerFromViewController:tbc.selectedViewController];
        } else {
            return viewController;
        }
    } else if (viewController.childViewControllers.count > 0) {
        UIViewController *childVC = [viewController childViewControllerForStatusBarStyle];
        
        if (childVC != nil) {
            return [self t_findTopViewControllerFromViewController:childVC];
        } else {
            return viewController;
        }
    } else if (viewController.presentedViewController) {
        if (@available(iOS 8.0, *)) {
            if ([viewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
                return viewController;
            }
        }
        return [self t_findTopViewControllerFromViewController:viewController.presentedViewController];
    } else {
        return viewController;
    }
}

@end


================================================
FILE: TLocationPlugin/Tools/UIWindow+TLocationPluginToast.h
================================================
//
//  UIWindow+TLocationPluginToast.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIWindow (TLocationPluginToast)

+ (void)t_showTostForMessage:(NSString *)message;
+ (void)t_showTostForMessage:(NSString *)message fontSize:(CGFloat)fontSize;

+ (void)t_showTostForCLLocation:(CLLocation *)location;
+ (void)t_showTostForCLLocations:(NSArray<CLLocation *> *)locations;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UIWindow+TLocationPluginToast.m
================================================
//
//  UIWindow+TLocationPluginToast.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "UIWindow+TLocationPluginToast.h"

#define SCREEN_HEIGHT   (UIScreen.mainScreen.bounds.size.height)
#define SCREEN_WIDTH    (UIScreen.mainScreen.bounds.size.width)

@implementation UIWindow (TLocationPluginToast)

static UIView *_t_cllocationToastView = nil;

+ (void)t_showTostForMessage:(NSString *)message
                    fontSize:(CGFloat)fontSize
                bottomMargin:(CGFloat)bottomMargin {
    dispatch_async(dispatch_get_main_queue(), ^{
        _t_cllocationToastView.hidden = YES;
        [_t_cllocationToastView removeFromSuperview];
        UIFont *textFont = [UIFont systemFontOfSize:fontSize];
        CGSize maxSize = CGSizeMake(200, 100);
        CGRect frame = [message boundingRectWithSize:maxSize
                                             options:NSStringDrawingUsesLineFragmentOrigin
                                          attributes:@{NSFontAttributeName: textFont}
                                             context:nil];
        frame = CGRectMake(0, 0, frame.size.width+40, frame.size.height+20);
        UIView *view = [[UIView alloc] initWithFrame:frame];
        
        UIView *bgView = [[UIView alloc] initWithFrame:frame];
        bgView.backgroundColor = UIColor.grayColor;
        bgView.alpha = 0.9;
        [view addSubview:bgView];
        
        UILabel *label = [[UILabel alloc] initWithFrame:frame];
        label.textColor = UIColor.whiteColor;
        label.textAlignment = NSTextAlignmentCenter;
        label.numberOfLines = 0;
        label.font = textFont;
        label.text = message;
        label.contentMode = UIViewContentModeCenter;
        [view addSubview:label];
        view.layer.cornerRadius = 5;
        view.layer.masksToBounds = YES;
        
        UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(_t_touchToastView:)];
        [view addGestureRecognizer:touch];
        [UIApplication.sharedApplication.keyWindow addSubview:view];
        CGFloat toastWidth = view.frame.size.width;
        CGFloat toastHeight = view.frame.size.height;
        CGFloat toastX = (SCREEN_WIDTH - toastWidth) / 2;
        CGFloat toastY = SCREEN_HEIGHT - toastHeight - bottomMargin;
        view.frame = CGRectMake(toastX, toastY, toastWidth, toastHeight);
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:0.5 animations:^{
                view.alpha = 0.0;
            } completion:^(BOOL finished) {
                [view removeFromSuperview];
                _t_cllocationToastView = nil;
            }];
        });
        _t_cllocationToastView = view;
    });
}

+ (void)t_showTostForMessage:(NSString *)message {
    [self t_showTostForMessage:message fontSize:12];
}

+ (void)t_showTostForMessage:(NSString *)message
                    fontSize:(CGFloat)fontSize {
    [self t_showTostForMessage:message
                      fontSize:fontSize
                  bottomMargin:100];
}

+ (void)t_showTostForCLLocation:(CLLocation *)location {
    if (location == nil) {
        return;
    }
    [self t_showTostForCLLocations:@[location]];
}

+ (void)t_showTostForCLLocations:(NSArray<CLLocation *> *)locations {
    if (locations.count == 0) {
        return;
    }
    NSMutableString *text = [NSMutableString string];
    for (NSUInteger idx = 0; idx < locations.count; ++idx) {
        CLLocation *location = locations[idx];
        if (idx == 0) [text appendString:@"定位数据"];
        [text appendString:@"\n"];
        [text appendString:@"纬度: "];
        [text appendString:@(location.coordinate.latitude).stringValue];
        [text appendString:@"\n"];
        [text appendString:@"经度: "];
        [text appendString:@(location.coordinate.longitude).stringValue];
    }
    [self t_showTostForMessage:text fontSize:10 bottomMargin:40];
}

+ (void)_t_touchToastView:(UIGestureRecognizer*)gestureRecognizer {
    [_t_cllocationToastView removeFromSuperview];
    _t_cllocationToastView = nil;
}

@end


================================================
FILE: TLocationPlugin/Tools/UIWindow+TLocationPluginTouch.h
================================================
//
//  UIWindow+TLocationPluginTouch.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIWindow (TLocationPluginTouch)

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/Tools/UIWindow+TLocationPluginTouch.m
================================================
//
//  UIWindow+TLocationPluginTouch.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <AudioToolbox/AudioToolbox.h>
#import "TSelectLocationDataViewController.h"
#import "TLocationNavigationController.h"
#import "UIWindow+TLocationPluginTouch.h"
#import "UIApplication+TLocationPlugin.h"

@implementation UIWindow (TLocationPluginTouch)

static NSInteger _t_windowTouchedTimes = 0;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if (TLocationNavigationController.isShowing) {
        return;
    }
    if (_t_windowTouchedTimes == 0) {
        // 开始触摸, 5秒后清零
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            _t_windowTouchedTimes = 0;
        });
    }
    ++_t_windowTouchedTimes;
    if (_t_windowTouchedTimes < 5) {
        return;
    }
    // 5秒内触摸5次
    TLocationNavigationController.isShowing = YES;
    _t_windowTouchedTimes = 0;
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
    UIViewController *rootVC = [UIApplication sharedApplication].t_topViewController;
    TSelectLocationDataViewController *vc = [[TSelectLocationDataViewController alloc] init];
    TLocationNavigationController *nav = [[TLocationNavigationController alloc] initWithRootViewController:vc];
    [rootVC presentViewController:nav animated:YES completion:^{
        [UIApplication.sharedApplication performSelector:@selector(setStatusBarStyle:animated:) withObject:@(UIStatusBarStyleDefault) withObject:@(YES)];
    }];
}
@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.h
================================================
//
//  TAddLocationDataViewController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TLocationModel.h"
#import "TBaseViewController.h"

NS_ASSUME_NONNULL_BEGIN

typedef void(^TAddLocationDataCompletionBlock)(TLocationModel *model);

@interface TAddLocationDataViewController : TBaseViewController

@property (nonatomic, copy) TAddLocationDataCompletionBlock addLocationBlock;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.m
================================================
//
//  TAddLocationDataViewController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "TAddLocationDataViewController.h"
#import "TLocationTableViewCell.h"
#import "TAlertController.h"
#import "UIImage+TLocationPlugin.h"
#import "UIWindow+TLocationPluginToast.h"

typedef void (^GetPlaceInfoBlock)(NSArray<TLocationModel *> *_Nullable models);

typedef NS_ENUM(NSUInteger, TMapViewAnnotationType) {
    TMapViewAnnotationTypeFirst,
    TMapViewAnnotationTypeAll,
};

static NSString * const TAddLocationDataTableViewCellID = @"TAddLocationDataTableViewCellID";

@interface TAddLocationDataViewController () <UITableViewDelegate, UITableViewDataSource, MKMapViewDelegate, UITextFieldDelegate>

@property (nonatomic, assign) BOOL shouldRefreshUserLocation;

@property (nonatomic, strong) IBOutlet UIView *searchContent;
@property (nonatomic, strong) IBOutlet UITextField *searchTextField;
@property (nonatomic, strong) IBOutlet MKMapView *mapView;
@property (nonatomic, strong) IBOutlet UITableView *tableView;

@property (nonatomic, copy) NSArray<TLocationModel *> *tableViewData;
@property (nonatomic, strong) TLocationModel *selectedModel;

@property (nonatomic, strong) CLLocationManager *locationManager;

@end

@implementation TAddLocationDataViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"添加位置";
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage t_imageNamed:@"user_location"]
                                                                              style:UIBarButtonItemStylePlain
                                                                             target:self
                                                                             action:@selector(backUserLocation:)];
    [self requestLocationAuthorization];
    if (self.mapView.userLocation.location) {
        [self refreshViewWithLocation:self.mapView.userLocation.location
                     setMapViewCenter:YES
                             animated:NO
                       annotationType:TMapViewAnnotationTypeFirst];
    }
    self.shouldRefreshUserLocation = YES;
    UITapGestureRecognizer *mapViewTouch = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                                   action:@selector(touchMapView:)];
    [self.mapView addGestureRecognizer:mapViewTouch];
    
    self.searchContent.layer.shadowColor = UIColor.blackColor.CGColor;
    self.searchContent.layer.shadowOpacity = 0.5;
    self.searchContent.layer.shadowOffset = CGSizeMake(0, 5);
    self.searchContent.layer.shadowRadius = 10;
}

- (void)requestLocationAuthorization {
    if (![CLLocationManager locationServicesEnabled]) {
        return;
    }
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse ||
        [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) {
        return;
    }
    self.locationManager = [[CLLocationManager alloc] init];
    [self.locationManager requestWhenInUseAuthorization];
}

- (void)touchMapView:(UIGestureRecognizer *)gestureRecognizer {
    if (self.searchTextField.isEditing) {
        [self.searchTextField resignFirstResponder];
        return;
    }
    self.shouldRefreshUserLocation = NO;
    CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView];
    CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint
                                                      toCoordinateFromView:self.mapView];
    CLLocation *location = [[CLLocation alloc] initWithLatitude:touchMapCoordinate.latitude
                                                      longitude:touchMapCoordinate.longitude];
    [self refreshViewWithLocation:location
                 setMapViewCenter:NO
                         animated:YES
                   annotationType:TMapViewAnnotationTypeFirst];
}

- (void)backUserLocation:(UIBarButtonItem *)sender {
    self.shouldRefreshUserLocation = YES;
    [self refreshViewWithLocation:self.mapView.userLocation.location
                 setMapViewCenter:YES
                         animated:NO
                   annotationType:TMapViewAnnotationTypeFirst];
}


- (IBAction)addALocationModelToLocalList:(UIButton *)sender {
    if (self.selectedModel == nil) {
        TAlertController *alert = [TAlertController singleActionAlertWithTitle:@"请选择一个位置"
                                                                       message:nil
                                                                   actionTitle:@"确定"
                                                                   actionBlock:nil];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }
    
    TAlertController *alert = [TAlertController editAlertWithTitle:@"请输入标记名称"
                                                           message:nil
                                                        labelTexts:nil
                                                     defaultValues:@[self.selectedModel.name ?: @""]
                                                       cancelTitle:@"取消"
                                                       cancelBlock:nil
                                                      confirmTitle:@"确定"
                                                      confirmBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
        NSString *name = alert.textFields.firstObject.text;
        [self saveSelectedModelWithNewName:name];
    }];
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)saveSelectedModelWithNewName:(NSString *)name {
    if (name.length <= 0) {
        TAlertController *alertError = [TAlertController singleActionAlertWithTitle:@"请输入标记名称"
                                                                            message:nil
                                                                        actionTitle:@"确定"
                                                                        actionBlock:nil];
        [self presentViewController:alertError animated:YES completion:nil];
        return;
    }
    
    /// 使用 copy 防止添加多次同一个对象出现问题
    TLocationModel *model = [self.selectedModel copy];
    model.name = name;
    /// 默认不选择
    model.isSelect = NO;
    if (self.addLocationBlock) {
        self.addLocationBlock(model);
        NSString *toastText = [NSString stringWithFormat:@"添加成功: %@\n%@", model.name, model.locationText];
        [UIWindow t_showTostForMessage:toastText];
    }
}

- (void)setMapViewCenter:(CLLocationCoordinate2D)coordinate animated:(BOOL)animated {
    self.mapView.centerCoordinate = coordinate;
    MKCoordinateSpan span = MKCoordinateSpanMake(0.0015, 0.0015);
    MKCoordinateRegion region = MKCoordinateRegionMake(coordinate, span);
    MKCoordinateRegion fitRegion = [self.mapView regionThatFits:region];
    if (CLLocationCoordinate2DIsValid(fitRegion.center)) {
        [self.mapView setRegion:fitRegion animated:animated];
    } else {
        [self.mapView setRegion:region animated:animated];
    }
}


- (void)updateTableViewForArray:(NSArray<TLocationModel *> *)array {
    /// 刷新清空
    self.selectedModel = nil;
    self.tableViewData = array;
    if (self.tableViewData.count > 0) {
        /// 默认选择第一个
        self.selectedModel = self.tableViewData.firstObject;
        self.selectedModel.isSelect = YES;
    }
    [self.tableView reloadData];
}

- (void)refreshAnnotationsForModelArray:(NSArray<TLocationModel *> *)modelArray {
    [self.mapView removeAnnotations:self.mapView.annotations];
    for (TLocationModel *model in modelArray) {
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(model.latitude, model.longitude);
        MKPointAnnotation *annoation = [[MKPointAnnotation alloc] init];
        annoation.coordinate = coordinate;
        annoation.title = model.name;
        [self.mapView addAnnotation:annoation];
    }
}

/// 刷新标记
- (void)refreshViewWithLocation:(CLLocation *)location
               setMapViewCenter:(BOOL)setMapViewCenter
                       animated:(BOOL)animated
                 annotationType:(TMapViewAnnotationType)annotationType {
    if (location == nil) {
        self.tableViewData = nil;
        [self.mapView removeAnnotations:self.mapView.annotations];
        [self.tableView reloadData];
        return;
    }
    if (setMapViewCenter) {
        [self setMapViewCenter:location.coordinate animated:animated];
    }
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        if (placemarks == nil) {
            self.tableViewData = nil;
            [self.mapView removeAnnotations:self.mapView.annotations];
            [self.tableView reloadData];
            return;
        }
        
        NSMutableArray<TLocationModel *> *locationModelArray = [NSMutableArray<TLocationModel *> array];
        for (CLPlacemark *placemark in placemarks) {
            TLocationModel *model =[TLocationModel modelWithSubLocality:placemark.subLocality
                                                                   name:placemark.name
                                                               latitude:placemark.location.coordinate.latitude
                                                              longitude:placemark.location.coordinate.longitude];
            [locationModelArray addObject:model];
        }
        
        if (annotationType == TMapViewAnnotationTypeFirst && locationModelArray.count >= 1) {
            [self refreshAnnotationsForModelArray:@[locationModelArray.firstObject]];
        } else {
            [self refreshAnnotationsForModelArray:locationModelArray];
        }
        [self updateTableViewForArray:locationModelArray];
    }];
}

- (IBAction)searchMap:(UIButton *)sender {
    [self.view endEditing:YES];
    [self searchMapForText:self.searchTextField.text];
}

/// 输入文字结束搜索, 其他情况不搜索
- (void)searchMapForText:(NSString *)text {
    if (text.length <= 0) {
        // 恢复用户当前位置
        self.shouldRefreshUserLocation = YES;
        [self refreshViewWithLocation:self.mapView.userLocation.location
                     setMapViewCenter:YES
                             animated:YES
                       annotationType:TMapViewAnnotationTypeFirst];
        return;
    }
    // 搜索则拦截用户位置更新, 不进行显示
    self.shouldRefreshUserLocation = NO;
    MKLocalSearchRequest *searchRequest = [[MKLocalSearchRequest alloc] init];
    [searchRequest setNaturalLanguageQuery:text];
    [searchRequest setRegion:self.mapView.region];
    MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:searchRequest];
    [localSearch startWithCompletionHandler:^(MKLocalSearchResponse * _Nullable response, NSError * _Nullable error) {
        // [self.mapView setRegion:response.boundingRegion];
        NSMutableArray<TLocationModel *> *locationModelArray = [NSMutableArray<TLocationModel *> array];
        for (MKMapItem *item in response.mapItems) {
            TLocationModel *model =[TLocationModel modelWithSubLocality:item.placemark.subLocality
                                                                   name:item.placemark.name
                                                               latitude:item.placemark.location.coordinate.latitude
                                                              longitude:item.placemark.location.coordinate.longitude];
            [locationModelArray addObject:model];
        }
        
        [self setMapViewCenter:response.mapItems.firstObject.placemark.location.coordinate
                      animated:YES];
        [self refreshAnnotationsForModelArray:locationModelArray];
        [self updateTableViewForArray:locationModelArray];
    }];
}

#pragma mark - UITableViewDelegate, UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableViewData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TLocationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TAddLocationDataTableViewCellID];
    if (cell == nil) {
        cell = [[TLocationTableViewCell alloc] initWithReuseIdentifier:TAddLocationDataTableViewCellID];
        cell.tableView = tableView;
    }
    cell.model = self.tableViewData[indexPath.row];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view endEditing:YES];
    self.shouldRefreshUserLocation = NO;
    
    NSMutableArray<NSIndexPath *> *reloadIndexPaths = [NSMutableArray<NSIndexPath *> array];
    [reloadIndexPaths addObject:indexPath];
    
    NSUInteger oldIndex = [self.tableViewData indexOfObject:self.selectedModel];
    if (oldIndex != NSNotFound) {
        NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:oldIndex inSection:0];
        [reloadIndexPaths addObject:oldIndexPath];
    }
    self.selectedModel.isSelect = NO;
    self.selectedModel = self.tableViewData[indexPath.row];
    self.selectedModel.isSelect = YES;
    [self.tableView reloadRowsAtIndexPaths:reloadIndexPaths
                          withRowAnimation:UITableViewRowAnimationNone];
    
    CLLocation *location = [[CLLocation alloc] initWithLatitude:self.selectedModel.latitude
                                                      longitude:self.selectedModel.longitude];
    [self setMapViewCenter:location.coordinate animated:NO];
}


#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    [self searchMapForText:textField.text];
    return YES;
}


#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(nonnull MKUserLocation *)userLocation {
    if (self.shouldRefreshUserLocation) {
        [self refreshViewWithLocation:userLocation.location
                     setMapViewCenter:YES
                             animated:YES
                       annotationType:TMapViewAnnotationTypeFirst];
    }
}

//- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
//}


@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina5_9" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TAddLocationDataViewController">
            <connections>
                <outlet property="mapView" destination="hQU-PM-GHy" id="1HW-Ec-v3n"/>
                <outlet property="searchContent" destination="Sfn-98-YBq" id="A2I-aO-zMc"/>
                <outlet property="searchTextField" destination="kYv-1g-b1a" id="PF8-wx-npV"/>
                <outlet property="tableView" destination="5p4-nj-99t" id="WZw-RW-BPT"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
            <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="D4z-bk-QeD">
                    <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
                    <subviews>
                        <mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" showsUserLocation="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hQU-PM-GHy">
                            <rect key="frame" x="0.0" y="0.0" width="375" height="406"/>
                            <connections>
                                <outlet property="delegate" destination="-1" id="n3U-Qu-00P"/>
                            </connections>
                        </mapView>
                        <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="5p4-nj-99t">
                            <rect key="frame" x="0.0" y="406" width="375" height="304"/>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <connections>
                                <outlet property="dataSource" destination="-1" id="d9K-Tp-6Tr"/>
                                <outlet property="delegate" destination="-1" id="i00-pc-pmt"/>
                            </connections>
                        </tableView>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="0jz-tV-Ftd">
                            <rect key="frame" x="8" y="720" width="359" height="40"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="40" id="jKX-Zi-9MV"/>
                            </constraints>
                            <state key="normal" title="添加">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="addALocationModelToLocalList:" destination="-1" eventType="touchUpInside" id="Qbc-c6-00S"/>
                            </connections>
                        </button>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Sfn-98-YBq">
                            <rect key="frame" x="20" y="62" width="335" height="40"/>
                            <subviews>
                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="搜索位置" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="kYv-1g-b1a">
                                    <rect key="frame" x="0.0" y="0.0" width="265" height="40"/>
                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="40" id="zL3-hg-lzl"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                    <textInputTraits key="textInputTraits" returnKeyType="search"/>
                                    <connections>
                                        <outlet property="delegate" destination="-1" id="Fvb-7M-vCS"/>
                                    </connections>
                                </textField>
                                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hOZ-Xi-8wG">
                                    <rect key="frame" x="265" y="0.0" width="70" height="40"/>
                                    <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <constraints>
                                        <constraint firstAttribute="width" constant="70" id="udo-Lc-e7c"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="16"/>
                                    <state key="normal" title="搜索">
                                        <color key="titleColor" red="0.97647058819999999" green="0.97647058819999999" blue="0.97647058819999999" alpha="1" colorSpace="calibratedRGB"/>
                                    </state>
                                    <connections>
                                        <action selector="searchMap:" destination="-1" eventType="touchUpInside" id="thq-tK-3E3"/>
                                    </connections>
                                </button>
                            </subviews>
                            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstItem="kYv-1g-b1a" firstAttribute="top" secondItem="Sfn-98-YBq" secondAttribute="top" id="QKe-s2-UNw"/>
                                <constraint firstAttribute="height" constant="40" id="RjG-ka-B17"/>
                                <constraint firstItem="kYv-1g-b1a" firstAttribute="leading" secondItem="Sfn-98-YBq" secondAttribute="leading" id="SE3-bX-zVG"/>
                                <constraint firstAttribute="trailing" secondItem="hOZ-Xi-8wG" secondAttribute="trailing" id="TXN-a1-qjJ"/>
                                <constraint firstItem="hOZ-Xi-8wG" firstAttribute="leading" secondItem="kYv-1g-b1a" secondAttribute="trailing" id="bnN-NR-wVd"/>
                                <constraint firstAttribute="bottom" secondItem="kYv-1g-b1a" secondAttribute="bottom" id="rJm-Y0-mLC"/>
                                <constraint firstAttribute="bottom" secondItem="hOZ-Xi-8wG" secondAttribute="bottom" id="rKD-Pn-PuO"/>
                                <constraint firstItem="hOZ-Xi-8wG" firstAttribute="top" secondItem="Sfn-98-YBq" secondAttribute="top" id="wo4-4i-qde"/>
                            </constraints>
                        </view>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <constraints>
                        <constraint firstItem="hQU-PM-GHy" firstAttribute="top" secondItem="D4z-bk-QeD" secondAttribute="top" id="0rc-Un-ucz"/>
                        <constraint firstItem="Sfn-98-YBq" firstAttribute="top" secondItem="D4z-bk-QeD" secondAttribute="topMargin" constant="10" id="4iG-O7-EuD"/>
                        <constraint firstItem="5p4-nj-99t" firstAttribute="leading" secondItem="D4z-bk-QeD" secondAttribute="leading" id="7Yg-wi-Nfh"/>
                        <constraint firstItem="0jz-tV-Ftd" firstAttribute="top" secondItem="5p4-nj-99t" secondAttribute="bottom" constant="10" id="E32-8V-vP5"/>
                        <constraint firstAttribute="trailingMargin" secondItem="0jz-tV-Ftd" secondAttribute="trailing" id="GIc-YZ-iyT"/>
                        <constraint firstItem="hQU-PM-GHy" firstAttribute="leading" secondItem="D4z-bk-QeD" secondAttribute="leading" id="IKR-Bq-B5I"/>
                        <constraint firstItem="5p4-nj-99t" firstAttribute="top" secondItem="hQU-PM-GHy" secondAttribute="bottom" id="LLJ-b7-CKy"/>
                        <constraint firstItem="Sfn-98-YBq" firstAttribute="leading" secondItem="D4z-bk-QeD" secondAttribute="leading" constant="20" id="NP0-cl-HrV"/>
                        <constraint firstAttribute="trailing" secondItem="hQU-PM-GHy" secondAttribute="trailing" id="OTf-aC-xnW"/>
                        <constraint firstItem="0jz-tV-Ftd" firstAttribute="leading" secondItem="D4z-bk-QeD" secondAttribute="leadingMargin" id="aIY-47-qUI"/>
                        <constraint firstItem="hQU-PM-GHy" firstAttribute="height" secondItem="D4z-bk-QeD" secondAttribute="height" multiplier="0.5" id="fVm-X9-nZ1"/>
                        <constraint firstAttribute="bottomMargin" secondItem="0jz-tV-Ftd" secondAttribute="bottom" constant="10" id="gM2-XT-GWW"/>
                        <constraint firstAttribute="trailing" secondItem="Sfn-98-YBq" secondAttribute="trailing" constant="20" id="gUV-mg-1pL"/>
                        <constraint firstAttribute="trailing" secondItem="5p4-nj-99t" secondAttribute="trailing" id="wxg-ut-0Ts"/>
                    </constraints>
                </view>
            </subviews>
            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
            <constraints>
                <constraint firstAttribute="trailing" secondItem="D4z-bk-QeD" secondAttribute="trailing" id="VGv-1R-eVD"/>
                <constraint firstItem="D4z-bk-QeD" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="Ypc-uT-1Fd"/>
                <constraint firstItem="D4z-bk-QeD" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="ddY-4Y-fQn"/>
                <constraint firstAttribute="bottom" secondItem="D4z-bk-QeD" secondAttribute="bottom" id="qb9-TF-Cpz"/>
            </constraints>
            <point key="canvasLocation" x="136.80000000000001" y="152.21674876847291"/>
        </view>
    </objects>
</document>


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TBaseViewController.h
================================================
//
//  TBaseViewController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface TBaseViewController : UIViewController

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TBaseViewController.m
================================================
//
//  TBaseViewController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TBaseViewController.h"
#import "NSBundle+TLocationPlugin.h"

@interface TBaseViewController ()

@end

@implementation TBaseViewController

- (instancetype)init {
    return [super initWithNibName:NSStringFromClass(self.class) bundle:NSBundle.t_bundle];
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleDefault;
}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.h
================================================
//
//  TLocationChangeAppICONViewController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/9.
//  Copyright © 2019 TBD. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TBaseViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface TLocationChangeAppICONViewController : TBaseViewController

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.m
================================================
//
//  TLocationChangeAppICONViewController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/9.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationChangeAppICONViewController.h"
#import "UIWindow+TLocationPluginToast.h"

@interface TLocationChangeAppICONViewController ()

@property (strong, nonatomic) IBOutlet UIButton *weWork;
@property (strong, nonatomic) IBOutlet UIButton *dingDing;
@property (strong, nonatomic) IBOutlet UIButton *lark;
@property (strong, nonatomic) IBOutlet UIButton *neiXin;
@property (strong, nonatomic) IBOutlet UIButton *qq;
@property (strong, nonatomic) IBOutlet UIButton *tim;
@property (strong, nonatomic) IBOutlet UIButton *weChat;

@end

@implementation TLocationChangeAppICONViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"修改图标";
}

- (IBAction)changeIconButtonClicked:(UIButton *)sender {
    if (@available(iOS 10.3, *)) {
        if (!UIApplication.sharedApplication.supportsAlternateIcons) {
            [UIWindow t_showTostForMessage:@"App不支持切换图标"];
            return;
        }
        
        NSString *iconName;
        if (sender == self.weWork) {
            iconName = @"WeWork";
        }
        if (sender == self.dingDing) {
            iconName = @"DingDing";
        }
        if (sender == self.lark) {
            iconName = @"Lark";
        }
        if (sender == self.neiXin) {
            iconName = @"NeiXin";
        }
        if (sender == self.qq) {
            iconName = @"QQ";
        }
        if (sender == self.tim) {
            iconName = @"Tim";
        }
        if (sender == self.weChat) {
            iconName = @"WeChat";
        }
        [UIApplication.sharedApplication setAlternateIconName:iconName completionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSString *toastMessage = [NSString stringWithFormat:@"App切换图标错误:\n%@", error];
                [UIWindow t_showTostForMessage:toastMessage];
            }
        }];
    } else {
        [UIWindow t_showTostForMessage:@"10.3以下系统不支持切换图标"];
    }
}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina5_9" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TLocationChangeAppICONViewController">
            <connections>
                <outlet property="dingDing" destination="Lrh-48-UxP" id="0wj-bn-Gsa"/>
                <outlet property="lark" destination="i06-1m-x0e" id="dsD-p1-Zpu"/>
                <outlet property="neiXin" destination="oZ9-Cp-bMe" id="fZC-gd-pM0"/>
                <outlet property="qq" destination="7pU-rl-Kdg" id="vNd-WG-6Su"/>
                <outlet property="tim" destination="4Hh-uh-57S" id="Y1u-0W-um3"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
                <outlet property="weChat" destination="b3X-ao-8Au" id="Bsn-de-sDN"/>
                <outlet property="weWork" destination="Ap9-PG-557" id="MLV-yO-9g2"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
            <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="7tt-7J-Jmy">
                    <rect key="frame" x="0.0" y="44" width="375" height="768"/>
                    <subviews>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ap9-PG-557">
                            <rect key="frame" x="8" y="20" width="175.66666666666666" height="87.666666666666671"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstAttribute="width" secondItem="Ap9-PG-557" secondAttribute="height" multiplier="2:1" id="bf0-Fg-8iQ"/>
                            </constraints>
                            <state key="normal" title="WeWork">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="Oi4-zS-qcu"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lrh-48-UxP">
                            <rect key="frame" x="191.66666666666663" y="20" width="175.33333333333337" height="87.666666666666671"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="DingDing">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="hvF-nu-EvK"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="i06-1m-x0e">
                            <rect key="frame" x="8" y="117.66666666666666" width="175.66666666666666" height="88"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="Lark">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="uFq-zt-WSH"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7pU-rl-Kdg">
                            <rect key="frame" x="8" y="215.66666666666666" width="175.66666666666666" height="87.666666666666657"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="QQ">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="okI-rv-qgZ"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="oZ9-Cp-bMe">
                            <rect key="frame" x="191.66666666666663" y="117.66666666666666" width="175.33333333333337" height="88"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="NeiXin">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="xTu-Ji-pTH"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Hh-uh-57S">
                            <rect key="frame" x="191.66666666666663" y="215.66666666666666" width="175.33333333333337" height="87.666666666666657"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="Tim">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="062-Qo-fcL"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="b3X-ao-8Au">
                            <rect key="frame" x="8" y="313.33333333333331" width="175.66666666666666" height="87.666666666666686"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <state key="normal" title="WeChat">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeIconButtonClicked:" destination="-1" eventType="touchUpInside" id="VBb-uP-lIy"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <constraints>
                        <constraint firstItem="i06-1m-x0e" firstAttribute="height" secondItem="Ap9-PG-557" secondAttribute="height" id="4dk-Cx-8GB"/>
                        <constraint firstItem="b3X-ao-8Au" firstAttribute="trailing" secondItem="7pU-rl-Kdg" secondAttribute="trailing" id="4fJ-Gx-n9b"/>
                        <constraint firstItem="oZ9-Cp-bMe" firstAttribute="trailing" secondItem="Lrh-48-UxP" secondAttribute="trailing" id="7CW-M5-cgP"/>
                        <constraint firstItem="i06-1m-x0e" firstAttribute="top" secondItem="Ap9-PG-557" secondAttribute="bottom" constant="10" id="GCI-nf-OFL"/>
                        <constraint firstItem="i06-1m-x0e" firstAttribute="trailing" secondItem="Ap9-PG-557" secondAttribute="trailing" id="Glj-Gc-kiO"/>
                        <constraint firstItem="Lrh-48-UxP" firstAttribute="bottom" secondItem="Ap9-PG-557" secondAttribute="bottom" id="I2F-55-Kvs"/>
                        <constraint firstItem="oZ9-Cp-bMe" firstAttribute="top" secondItem="i06-1m-x0e" secondAttribute="top" id="J4j-SV-dEM"/>
                        <constraint firstItem="oZ9-Cp-bMe" firstAttribute="bottom" secondItem="i06-1m-x0e" secondAttribute="bottom" id="Kh5-a7-zyD"/>
                        <constraint firstAttribute="trailingMargin" secondItem="Lrh-48-UxP" secondAttribute="trailing" id="LoJ-pG-atU"/>
                        <constraint firstItem="7pU-rl-Kdg" firstAttribute="height" secondItem="i06-1m-x0e" secondAttribute="height" id="QHO-pR-0QN"/>
                        <constraint firstItem="7pU-rl-Kdg" firstAttribute="trailing" secondItem="i06-1m-x0e" secondAttribute="trailing" id="Tdx-mc-MR5"/>
                        <constraint firstItem="7pU-rl-Kdg" firstAttribute="leading" secondItem="i06-1m-x0e" secondAttribute="leading" id="XvG-oj-rHb"/>
                        <constraint firstItem="Lrh-48-UxP" firstAttribute="top" secondItem="Ap9-PG-557" secondAttribute="top" id="ZYE-bb-mLz"/>
                        <constraint firstItem="Ap9-PG-557" firstAttribute="width" secondItem="7tt-7J-Jmy" secondAttribute="width" multiplier="0.5" constant="-12" id="cFd-X4-W6f"/>
                        <constraint firstItem="4Hh-uh-57S" firstAttribute="leading" secondItem="oZ9-Cp-bMe" secondAttribute="leading" id="elX-ae-97T"/>
                        <constraint firstItem="Ap9-PG-557" firstAttribute="top" secondItem="7tt-7J-Jmy" secondAttribute="top" constant="20" id="gF7-no-kIZ"/>
                        <constraint firstItem="b3X-ao-8Au" firstAttribute="height" secondItem="7pU-rl-Kdg" secondAttribute="height" id="hVb-nk-YyG"/>
                        <constraint firstItem="b3X-ao-8Au" firstAttribute="top" secondItem="7pU-rl-Kdg" secondAttribute="bottom" constant="10" id="iyl-v6-mZk"/>
                        <constraint firstItem="oZ9-Cp-bMe" firstAttribute="leading" secondItem="Lrh-48-UxP" secondAttribute="leading" id="jz0-qY-TMa"/>
                        <constraint firstItem="7pU-rl-Kdg" firstAttribute="top" secondItem="i06-1m-x0e" secondAttribute="bottom" constant="10" id="kuV-7g-YLO"/>
                        <constraint firstItem="b3X-ao-8Au" firstAttribute="leading" secondItem="7pU-rl-Kdg" secondAttribute="leading" id="n5o-MM-99H"/>
                        <constraint firstItem="4Hh-uh-57S" firstAttribute="top" secondItem="7pU-rl-Kdg" secondAttribute="top" id="oFa-4v-KS2"/>
                        <constraint firstItem="Ap9-PG-557" firstAttribute="leading" secondItem="7tt-7J-Jmy" secondAttribute="leadingMargin" id="oRa-QU-2ZY"/>
                        <constraint firstItem="Lrh-48-UxP" firstAttribute="width" secondItem="Ap9-PG-557" secondAttribute="width" id="odq-c0-6gy"/>
                        <constraint firstItem="4Hh-uh-57S" firstAttribute="trailing" secondItem="oZ9-Cp-bMe" secondAttribute="trailing" id="vOU-ne-rnZ"/>
                        <constraint firstItem="i06-1m-x0e" firstAttribute="leading" secondItem="Ap9-PG-557" secondAttribute="leading" id="veX-MT-nUh"/>
                        <constraint firstItem="4Hh-uh-57S" firstAttribute="bottom" secondItem="7pU-rl-Kdg" secondAttribute="bottom" id="yky-SU-TZc"/>
                    </constraints>
                </view>
            </subviews>
            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
            <constraints>
                <constraint firstItem="7tt-7J-Jmy" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="topMargin" id="EMG-gG-iCo"/>
                <constraint firstAttribute="bottom" secondItem="7tt-7J-Jmy" secondAttribute="bottom" id="IV2-5m-xEj"/>
                <constraint firstItem="7tt-7J-Jmy" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="Zc7-6h-dbS"/>
                <constraint firstAttribute="trailing" secondItem="7tt-7J-Jmy" secondAttribute="trailing" id="r3t-iv-zvd"/>
            </constraints>
            <point key="canvasLocation" x="-68.115942028985515" y="152.67857142857142"/>
        </view>
    </objects>
</document>


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationNavigationController.h
================================================
//
//  TLocationNavigationController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface TLocationNavigationController : UINavigationController

@property(class, nonatomic, assign) BOOL isShowing;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationNavigationController.m
================================================
//
//  TLocationNavigationController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationNavigationController.h"
#import "UIImage+TLocationPlugin.h"
#import "TLocationManager.h"

@interface TLocationNavigationController ()

@property (nonatomic, assign) UIStatusBarStyle currentStatusBarStyle;

@end

@implementation TLocationNavigationController

- (void)dealloc {
    TLocationNavigationController.isShowing = NO;
    /// restore old style
    [UIApplication sharedApplication].statusBarStyle = self.currentStatusBarStyle;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    /// save old style
    self.currentStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
    self.view.backgroundColor = UIColor.whiteColor;
    
    self.navigationBar.shadowImage = nil;
    self.navigationBar.tintColor = UIColor.whiteColor;
    self.navigationBar.tintColor = UIColor.blackColor;
    self.navigationBar.titleTextAttributes = @{
        NSForegroundColorAttributeName: UIColor.blackColor,
        NSFontAttributeName: [UIFont boldSystemFontOfSize:17],
    };
}

#pragma mark - Setter/Getter
static BOOL _t_isShowing = NO;
+ (BOOL)isShowing {
    return _t_isShowing;
}

+ (void)setIsShowing:(BOOL)isShowing {
    _t_isShowing = isShowing;
    TLocationManager.shared.suspend = isShowing;
}


- (UIModalPresentationStyle)modalPresentationStyle {
    return UIModalPresentationFullScreen;
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleDefault;
}

- (UIViewController *)childViewControllerForStatusBarStyle {
    return nil;
}

- (UIViewController *)childViewControllerForStatusBarHidden {
    return nil;
}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.h
================================================
//
//  TLocationSettingViewController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TBaseViewController.h"

NS_ASSUME_NONNULL_BEGIN

@interface TLocationSettingViewController : TBaseViewController

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.m
================================================
//
//  TLocationSettingViewController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationSettingViewController.h"
#import "TSelectLocationDataViewController.h"
#import "TLocationManager.h"
#import "UIImage+TLocationPlugin.h"
#import "TAlertController.h"
#import "UIWindow+TLocationPluginToast.h"
#import "TLocationChangeAppICONViewController.h"

@interface TLocationSettingViewController () <UITextFieldDelegate>

@property (nonatomic, strong) IBOutlet UIScrollView *contentScrollView;
@property (nonatomic, strong) IBOutlet UILabel *locationNameLabel;
@property (nonatomic, strong) IBOutlet UITextField *latitudeTextField;
@property (nonatomic, strong) IBOutlet UITextField *longitudeTextField;
@property (nonatomic, strong) IBOutlet UITextField *rangeTextField;
@property (nonatomic, strong) IBOutlet UISwitch *usingHookSwitch;
@property (strong, nonatomic) IBOutlet UISwitch *usingToastSwitch;

@end

@implementation TLocationSettingViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"设置";
    UITapGestureRecognizer *sigleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                               action:@selector(tapScrollView)];
    [self.contentScrollView addGestureRecognizer:sigleTap];
    NSString *locationName = TLocationManager.shared.locationName;
    CLLocationDegrees latitude = TLocationManager.shared.latitude;
    CLLocationDegrees longitude = TLocationManager.shared.longitude;
    NSInteger range = TLocationManager.shared.range;
    BOOL isUsingHook = TLocationManager.shared.usingHookLocation;
    BOOL isUsingToast = TLocationManager.shared.usingToast;
    self.locationNameLabel.text = locationName;
    self.latitudeTextField.text = @(latitude).stringValue;
    self.longitudeTextField.text = @(longitude).stringValue;
    self.rangeTextField.text = @(range).stringValue;
    self.usingHookSwitch.on = isUsingHook;
    self.usingToastSwitch.on = isUsingToast;
}

- (void)tapScrollView {
    [self.view endEditing:YES];
}

/// 开关
- (IBAction)usingHookLocationValueChanged:(UISwitch *)sender {
    [self.view endEditing:YES];
    TLocationManager.shared.usingHookLocation = sender.isOn;
    [UIWindow t_showTostForMessage:sender.isOn ? @"已开启位置拦截" : @"已关闭位置拦截"];
}

- (IBAction)usingToastValueChanged:(UISwitch *)sender {
    [self.view endEditing:YES];
    TLocationManager.shared.usingToast = sender.isOn;
    [UIWindow t_showTostForMessage:sender.isOn ? @"已开启定位提示" : @"已关闭定位提示"];
}

- (IBAction)changeAppICON:(UIButton *)sender {
    TLocationChangeAppICONViewController *vc = [[TLocationChangeAppICONViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

- (IBAction)cleanCacheData:(UIButton *)sender {
    TAlertController *alert = [TAlertController destructiveAlertWithTitle:@"确定清空保存的位置列表数据?"
                                                                  message:nil
                                                              cancelTitle:@"取消"
                                                              cancelBlock:nil
                                                         destructiveTitle:@"确定"
                                                         destructiveBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
        TLocationManager.shared.cacheDataArray = nil;
        [TLocationManager.shared saveCacheDataArray];
        [UIWindow t_showTostForMessage:@"已清空保存的位置列表数据"];
    }];
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [self.view endEditing:YES];
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    if (textField == self.rangeTextField) {
        NSInteger range = [self.rangeTextField.text integerValue];
        if (TLocationManager.shared.range != range) {
            TLocationManager.shared.range = range;
            NSString *tostText = [NSString stringWithFormat:@"已保存范围: %ld", (long)TLocationManager.shared.range];
            // 重设值, TLocationManager.shared.range 赋值包含判断
            textField.text = @(TLocationManager.shared.range).stringValue;
            [UIWindow t_showTostForMessage:tostText];
        }
    }
    return YES;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina5_9" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <objects>
        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TLocationSettingViewController">
            <connections>
                <outlet property="contentScrollView" destination="hky-M3-ICB" id="TMf-mn-veE"/>
                <outlet property="latitudeTextField" destination="K2X-fA-dZd" id="Y5T-8s-AEj"/>
                <outlet property="locationNameLabel" destination="Cwa-lD-bT9" id="opb-VE-UWZ"/>
                <outlet property="longitudeTextField" destination="AvS-No-Mxt" id="icf-Ao-wcr"/>
                <outlet property="rangeTextField" destination="ggQ-Zj-etz" id="vw6-fr-idL"/>
                <outlet property="usingHookSwitch" destination="3yV-UL-fdM" id="BpI-np-Exb"/>
                <outlet property="usingToastSwitch" destination="dAi-MM-MGR" id="fz5-hF-Byt"/>
                <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
            </connections>
        </placeholder>
        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
        <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
            <rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
            <subviews>
                <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hky-M3-ICB">
                    <rect key="frame" x="0.0" y="44" width="375" height="768"/>
                    <subviews>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sE3-RS-abB" userLabel="位置">
                            <rect key="frame" x="16" y="40" width="343" height="152"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="位置信息" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zYq-f4-Bgb">
                                    <rect key="frame" x="20" y="0.0" width="303" height="40"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="40" id="i1h-mS-dj1"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="name" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Cwa-lD-bT9">
                                    <rect key="frame" x="20" y="40" width="303" height="17"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="纬度:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qxb-h7-Vzw">
                                    <rect key="frame" x="20" y="67" width="40" height="30"/>
                                    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="30" id="ISR-zi-9BW"/>
                                        <constraint firstAttribute="width" constant="40" id="M8Z-hk-dHy"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="经度:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aqZ-hf-K3S">
                                    <rect key="frame" x="20" y="102" width="40" height="30"/>
                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <textField opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="K2X-fA-dZd">
                                    <rect key="frame" x="70" y="67" width="253" height="30"/>
                                    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="15"/>
                                    <textInputTraits key="textInputTraits" keyboardType="decimalPad" returnKeyType="next"/>
                                    <connections>
                                        <outlet property="delegate" destination="-1" id="O96-EE-yU0"/>
                                    </connections>
                                </textField>
                                <textField opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="AvS-No-Mxt">
                                    <rect key="frame" x="70" y="102" width="253" height="30"/>
                                    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="15"/>
                                    <textInputTraits key="textInputTraits" keyboardType="decimalPad" returnKeyType="next"/>
                                    <connections>
                                        <outlet property="delegate" destination="-1" id="PEk-vL-zzD"/>
                                    </connections>
                                </textField>
                            </subviews>
                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstItem="K2X-fA-dZd" firstAttribute="leading" secondItem="qxb-h7-Vzw" secondAttribute="trailing" constant="10" id="1QS-05-bTf"/>
                                <constraint firstItem="qxb-h7-Vzw" firstAttribute="leading" secondItem="sE3-RS-abB" secondAttribute="leading" constant="20" id="2sG-mg-WJN"/>
                                <constraint firstItem="aqZ-hf-K3S" firstAttribute="top" secondItem="qxb-h7-Vzw" secondAttribute="bottom" constant="5" id="2yL-Qx-6f7"/>
                                <constraint firstItem="zYq-f4-Bgb" firstAttribute="top" secondItem="sE3-RS-abB" secondAttribute="top" id="3bk-QE-vl3"/>
                                <constraint firstItem="Cwa-lD-bT9" firstAttribute="leading" secondItem="sE3-RS-abB" secondAttribute="leading" constant="20" id="4V9-jZ-ble"/>
                                <constraint firstItem="AvS-No-Mxt" firstAttribute="leading" secondItem="K2X-fA-dZd" secondAttribute="leading" id="88J-Wr-7NQ"/>
                                <constraint firstItem="Cwa-lD-bT9" firstAttribute="top" secondItem="zYq-f4-Bgb" secondAttribute="bottom" id="JIu-Us-L1j"/>
                                <constraint firstItem="AvS-No-Mxt" firstAttribute="top" secondItem="aqZ-hf-K3S" secondAttribute="top" id="LFg-O1-7pA"/>
                                <constraint firstItem="qxb-h7-Vzw" firstAttribute="top" secondItem="Cwa-lD-bT9" secondAttribute="bottom" constant="10" id="OVf-pS-k9p"/>
                                <constraint firstItem="aqZ-hf-K3S" firstAttribute="leading" secondItem="qxb-h7-Vzw" secondAttribute="leading" id="OgP-e4-Efh"/>
                                <constraint firstItem="K2X-fA-dZd" firstAttribute="top" secondItem="qxb-h7-Vzw" secondAttribute="top" id="QYH-qE-rGR"/>
                                <constraint firstItem="K2X-fA-dZd" firstAttribute="bottom" secondItem="qxb-h7-Vzw" secondAttribute="bottom" id="Qwn-xG-Buz"/>
                                <constraint firstAttribute="trailing" secondItem="Cwa-lD-bT9" secondAttribute="trailing" constant="20" id="Rii-aB-TTR"/>
                                <constraint firstItem="zYq-f4-Bgb" firstAttribute="leading" secondItem="sE3-RS-abB" secondAttribute="leading" constant="20" id="S1u-Ii-KF4"/>
                                <constraint firstAttribute="trailing" secondItem="K2X-fA-dZd" secondAttribute="trailing" constant="20" id="TUZ-51-tIa"/>
                                <constraint firstItem="AvS-No-Mxt" firstAttribute="trailing" secondItem="K2X-fA-dZd" secondAttribute="trailing" id="Tm3-d7-k4T"/>
                                <constraint firstItem="aqZ-hf-K3S" firstAttribute="height" secondItem="qxb-h7-Vzw" secondAttribute="height" id="YzI-CY-Qnf"/>
                                <constraint firstItem="aqZ-hf-K3S" firstAttribute="width" secondItem="qxb-h7-Vzw" secondAttribute="width" id="ZAg-aR-wK1"/>
                                <constraint firstAttribute="bottom" secondItem="aqZ-hf-K3S" secondAttribute="bottom" constant="20" id="ej5-KE-Fnf"/>
                                <constraint firstAttribute="trailing" secondItem="zYq-f4-Bgb" secondAttribute="trailing" constant="20" id="k3k-cv-JCF"/>
                                <constraint firstItem="AvS-No-Mxt" firstAttribute="bottom" secondItem="aqZ-hf-K3S" secondAttribute="bottom" id="pCI-rB-sxW"/>
                            </constraints>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                <userDefinedRuntimeAttribute type="color" keyPath="layer.t_borderUIColor">
                                    <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
                                    <integer key="value" value="1"/>
                                </userDefinedRuntimeAttribute>
                            </userDefinedRuntimeAttributes>
                        </view>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Pye-GT-934" userLabel="范围">
                            <rect key="frame" x="16" y="212" width="343" height="90"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="范围设置" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1es-Ok-4Z1">
                                    <rect key="frame" x="20" y="0.0" width="303" height="40"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="40" id="vkS-Gr-nqd"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="范围:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fO8-Y8-GiO">
                                    <rect key="frame" x="20" y="40" width="35" height="30"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="30" id="Tkh-yi-Aej"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="ggQ-Zj-etz">
                                    <rect key="frame" x="65" y="40" width="258" height="30"/>
                                    <color key="tintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="15"/>
                                    <textInputTraits key="textInputTraits" keyboardType="numberPad" returnKeyType="done"/>
                                    <connections>
                                        <outlet property="delegate" destination="-1" id="H3U-gv-Jzo"/>
                                    </connections>
                                </textField>
                            </subviews>
                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstItem="ggQ-Zj-etz" firstAttribute="bottom" secondItem="fO8-Y8-GiO" secondAttribute="bottom" id="4n8-hf-IZv"/>
                                <constraint firstItem="ggQ-Zj-etz" firstAttribute="top" secondItem="fO8-Y8-GiO" secondAttribute="top" id="9Ss-ge-H7f"/>
                                <constraint firstItem="1es-Ok-4Z1" firstAttribute="top" secondItem="Pye-GT-934" secondAttribute="top" id="G3p-Ap-0hh"/>
                                <constraint firstAttribute="bottom" secondItem="fO8-Y8-GiO" secondAttribute="bottom" constant="20" id="U50-w6-aAA"/>
                                <constraint firstAttribute="trailing" secondItem="ggQ-Zj-etz" secondAttribute="trailing" constant="20" id="UHd-uZ-rTq"/>
                                <constraint firstItem="1es-Ok-4Z1" firstAttribute="leading" secondItem="Pye-GT-934" secondAttribute="leading" constant="20" id="fJh-0C-dac"/>
                                <constraint firstAttribute="trailing" secondItem="1es-Ok-4Z1" secondAttribute="trailing" constant="20" id="io3-qm-vJy"/>
                                <constraint firstItem="fO8-Y8-GiO" firstAttribute="leading" secondItem="Pye-GT-934" secondAttribute="leading" constant="20" id="lUM-oG-Lrr"/>
                                <constraint firstItem="fO8-Y8-GiO" firstAttribute="top" secondItem="1es-Ok-4Z1" secondAttribute="bottom" id="mSA-5n-I3I"/>
                                <constraint firstItem="ggQ-Zj-etz" firstAttribute="leading" secondItem="fO8-Y8-GiO" secondAttribute="trailing" constant="10" id="rpT-Rr-wPa"/>
                            </constraints>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                <userDefinedRuntimeAttribute type="color" keyPath="layer.t_borderUIColor">
                                    <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
                                    <integer key="value" value="1"/>
                                </userDefinedRuntimeAttribute>
                            </userDefinedRuntimeAttributes>
                        </view>
                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Nf7-hy-6Ad" userLabel="开关">
                            <rect key="frame" x="16" y="322" width="343" height="120"/>
                            <subviews>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="开关设置" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cq3-28-tDd">
                                    <rect key="frame" x="20" y="0.0" width="303" height="40"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="40" id="nZH-Gs-zv9"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="启用位置拦截" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fk5-72-04V">
                                    <rect key="frame" x="20" y="40" width="234" height="25"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="25" id="HvL-fG-1qR"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="3yV-UL-fdM">
                                    <rect key="frame" x="274" y="37.666666666666686" width="51" height="30"/>
                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="30" id="TkI-E9-4QV"/>
                                        <constraint firstAttribute="width" constant="49" id="ZjS-qg-Flc"/>
                                    </constraints>
                                    <color key="onTintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="thumbTintColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <connections>
                                        <action selector="usingHookLocationValueChanged:" destination="-1" eventType="valueChanged" id="PTp-Wv-nfG"/>
                                    </connections>
                                </switch>
                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="启用定位提示" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="R9R-aL-Sn4">
                                    <rect key="frame" x="20" y="75" width="234" height="25"/>
                                    <constraints>
                                        <constraint firstAttribute="height" constant="25" id="YB0-al-PEv"/>
                                    </constraints>
                                    <fontDescription key="fontDescription" type="system" pointSize="15"/>
                                    <nil key="textColor"/>
                                    <nil key="highlightedColor"/>
                                </label>
                                <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="dAi-MM-MGR">
                                    <rect key="frame" x="274" y="72.666666666666686" width="51" height="30"/>
                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="onTintColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                    <color key="thumbTintColor" systemColor="systemGrayColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                    <connections>
                                        <action selector="usingToastValueChanged:" destination="-1" eventType="valueChanged" id="zMT-qb-5KG"/>
                                    </connections>
                                </switch>
                            </subviews>
                            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstItem="dAi-MM-MGR" firstAttribute="leading" secondItem="3yV-UL-fdM" secondAttribute="leading" id="3en-b5-RZ7"/>
                                <constraint firstItem="dAi-MM-MGR" firstAttribute="height" secondItem="3yV-UL-fdM" secondAttribute="height" id="Avg-og-6Kc"/>
                                <constraint firstItem="dAi-MM-MGR" firstAttribute="trailing" secondItem="3yV-UL-fdM" secondAttribute="trailing" id="F5N-2E-eNr"/>
                                <constraint firstItem="R9R-aL-Sn4" firstAttribute="top" secondItem="fk5-72-04V" secondAttribute="bottom" constant="10" id="Ftd-pa-ZB5"/>
                                <constraint firstItem="cq3-28-tDd" firstAttribute="leading" secondItem="Nf7-hy-6Ad" secondAttribute="leading" constant="20" id="Z4F-dO-Bmu"/>
                                <constraint firstItem="3yV-UL-fdM" firstAttribute="centerY" secondItem="fk5-72-04V" secondAttribute="centerY" id="a3Z-uh-Ok2"/>
                                <constraint firstItem="cq3-28-tDd" firstAttribute="top" secondItem="Nf7-hy-6Ad" secondAttribute="top" id="aTx-vQ-221"/>
                                <constraint firstItem="3yV-UL-fdM" firstAttribute="trailing" secondItem="cq3-28-tDd" secondAttribute="trailing" id="hBN-ph-du0"/>
                                <constraint firstItem="fk5-72-04V" firstAttribute="leading" secondItem="cq3-28-tDd" secondAttribute="leading" id="ifi-n8-nuU"/>
                                <constraint firstAttribute="bottom" secondItem="R9R-aL-Sn4" secondAttribute="bottom" constant="20" id="iuQ-vW-A1d"/>
                                <constraint firstItem="fk5-72-04V" firstAttribute="top" secondItem="cq3-28-tDd" secondAttribute="bottom" id="kXR-d6-tg6"/>
                                <constraint firstItem="dAi-MM-MGR" firstAttribute="centerY" secondItem="R9R-aL-Sn4" secondAttribute="centerY" id="mAG-5S-nUC"/>
                                <constraint firstAttribute="trailing" secondItem="cq3-28-tDd" secondAttribute="trailing" constant="20" id="nXv-pQ-06F"/>
                                <constraint firstItem="3yV-UL-fdM" firstAttribute="leading" secondItem="fk5-72-04V" secondAttribute="trailing" constant="20" id="p3F-1l-0mX"/>
                                <constraint firstItem="R9R-aL-Sn4" firstAttribute="trailing" secondItem="fk5-72-04V" secondAttribute="trailing" id="rko-V4-BHF"/>
                                <constraint firstItem="R9R-aL-Sn4" firstAttribute="leading" secondItem="fk5-72-04V" secondAttribute="leading" id="ueI-WS-3O8"/>
                            </constraints>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                                <userDefinedRuntimeAttribute type="color" keyPath="layer.t_borderUIColor">
                                    <color key="value" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.borderWidth">
                                    <integer key="value" value="1"/>
                                </userDefinedRuntimeAttribute>
                            </userDefinedRuntimeAttributes>
                        </view>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="LV1-LM-h2q">
                            <rect key="frame" x="16" y="552" width="343" height="40"/>
                            <color key="backgroundColor" red="1" green="0.0" blue="0.20679030879001292" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="40" id="bil-oO-rV9"/>
                            </constraints>
                            <state key="normal" title="清空缓存列表">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="cleanCacheData:" destination="-1" eventType="touchUpInside" id="LP7-fr-LaM"/>
                            </connections>
                        </button>
                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="fPk-yc-8np">
                            <rect key="frame" x="16" y="492" width="343" height="40"/>
                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            <constraints>
                                <constraint firstAttribute="height" constant="40" id="7C9-GN-RTM"/>
                            </constraints>
                            <state key="normal" title="修改图标">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <state key="highlighted">
                                <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                            </state>
                            <userDefinedRuntimeAttributes>
                                <userDefinedRuntimeAttribute type="number" keyPath="layer.cornerRadius">
                                    <integer key="value" value="5"/>
                                </userDefinedRuntimeAttribute>
                                <userDefinedRuntimeAttribute type="boolean" keyPath="layer.masksToBounds" value="YES"/>
                            </userDefinedRuntimeAttributes>
                            <connections>
                                <action selector="changeAppICON:" destination="-1" eventType="touchUpInside" id="c6u-Uf-sXB"/>
                            </connections>
                        </button>
                    </subviews>
                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                    <constraints>
                        <constraint firstItem="fPk-yc-8np" firstAttribute="leading" secondItem="Nf7-hy-6Ad" secondAttribute="leading" id="0u9-h2-L0m"/>
                        <constraint firstItem="sE3-RS-abB" firstAttribute="top" secondItem="hky-M3-ICB" secondAttribute="top" constant="40" id="4Ys-VA-I9j"/>
                        <constraint firstItem="Pye-GT-934" firstAttribute="leading" secondItem="sE3-RS-abB" secondAttribute="leading" id="9Wq-fc-aZF"/>
                        <constraint firstItem="Nf7-hy-6Ad" firstAttribute="trailing" secondItem="Pye-GT-934" secondAttribute="trailing" id="BrH-CT-lKX"/>
                        <constraint firstItem="sE3-RS-abB" firstAttribute="leading" secondItem="hky-M3-ICB" secondAttribute="leading" constant="16" id="D00-6D-dU0"/>
                        <constraint firstItem="Nf7-hy-6Ad" firstAttribute="leading" secondItem="Pye-GT-934" secondAttribute="leading" id="Fa0-Ba-XKy"/>
                        <constraint firstItem="sE3-RS-abB" firstAttribute="width" secondItem="hky-M3-ICB" secondAttribute="width" constant="-32" id="Hz7-ON-TT5"/>
                        <constraint firstAttribute="trailing" secondItem="sE3-RS-abB" secondAttribute="trailing" constant="16" id="JBy-ZY-dk6"/>
                        <constraint firstItem="LV1-LM-h2q" firstAttribute="leading" secondItem="fPk-yc-8np" secondAttribute="leading" id="PEj-EN-02j"/>
                        <constraint firstItem="Nf7-hy-6Ad" firstAttribute="top" secondItem="Pye-GT-934" secondAttribute="bottom" constant="20" id="RGb-pm-NXk"/>
                        <constraint firstItem="Pye-GT-934" firstAttribute="trailing" secondItem="sE3-RS-abB" secondAttribute="trailing" id="Wf1-AG-igz"/>
                        <constraint firstAttribute="bottom" secondItem="LV1-LM-h2q" secondAttribute="bottom" constant="40" id="YsV-cZ-Amx"/>
                        <constraint firstItem="fPk-yc-8np" firstAttribute="trailing" secondItem="Nf7-hy-6Ad" secondAttribute="trailing" id="agg-hg-dT6"/>
                        <constraint firstItem="Pye-GT-934" firstAttribute="top" secondItem="sE3-RS-abB" secondAttribute="bottom" constant="20" id="i0V-M6-e7W"/>
                        <constraint firstItem="fPk-yc-8np" firstAttribute="top" secondItem="Nf7-hy-6Ad" secondAttribute="bottom" constant="50" id="nZq-8d-3Yj"/>
                        <constraint firstItem="LV1-LM-h2q" firstAttribute="top" secondItem="fPk-yc-8np" secondAttribute="bottom" constant="20" id="xjv-px-Ugr"/>
                        <constraint firstItem="LV1-LM-h2q" firstAttribute="trailing" secondItem="fPk-yc-8np" secondAttribute="trailing" id="zfV-df-0ob"/>
                    </constraints>
                </scrollView>
            </subviews>
            <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
            <constraints>
                <constraint firstItem="hky-M3-ICB" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="topMargin" id="0VV-fZ-0TR"/>
                <constraint firstAttribute="trailing" secondItem="hky-M3-ICB" secondAttribute="trailing" id="Zjg-Y8-e79"/>
                <constraint firstAttribute="bottom" secondItem="hky-M3-ICB" secondAttribute="bottom" id="qzT-Iv-tIW"/>
                <constraint firstItem="hky-M3-ICB" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" id="tsg-Yg-EV6"/>
            </constraints>
            <point key="canvasLocation" x="-196" y="137.4384236453202"/>
        </view>
    </objects>
</document>


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationTableViewCell.h
================================================
//
//  TLocationTableViewCell.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TLocationModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface TLocationTableViewCell : UITableViewCell

@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, weak) TLocationModel *model;

- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;

//- (void)setSelectedCell:(BOOL)selected;

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationTableViewCell.m
================================================
//
//  TLocationTableViewCell.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/5.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TLocationTableViewCell.h"
#import "UIImage+TLocationPlugin.h"
#import "UITableView+TLocationPlugin.h"

@implementation TLocationTableViewCell

- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];
    if (self) {
        self.selectionStyle = UITableViewCellSelectionStyleGray;
        self.selectedBackgroundView = [[UIView alloc] init];
        self.textLabel.numberOfLines = 0;
        self.textLabel.font = [UIFont boldSystemFontOfSize:16];
        self.detailTextLabel.numberOfLines = 0;
        self.detailTextLabel.textColor = UIColor.darkGrayColor;
        self.detailTextLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12];
        self.tintColor = UIColor.blackColor;
    }
    return self;
}

- (void)awakeFromNib {
    [super awakeFromNib];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
    if (self.tableView.isEditing || self.tableView.isEditBegining) {
        return;
    }
}

- (void)setModel:(TLocationModel *)model {
    self->_model = model;
    
    if (model.isSelect) {
        self.imageView.image = [UIImage t_imageNamed:@"checked_location"];
    } else {
        self.imageView.image = [UIImage t_imageNamed:@"none"];
    }
    self.textLabel.text = model.name;
    self.detailTextLabel.text = model.locationText;
}

///// 添加选择方法为了防止和编辑模式下默认的 select 冲突
//- (void)setSelectedCell:(BOOL)selected {
//    if (selected) {
//        self.imageView.image = [UIImage t_imageNamed:@"checked_location"];
//    } else {
//        self.imageView.image = [UIImage t_imageNamed:@"none"];
//    }
//}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.h
================================================
//
//  TSelectLocationDataViewController.h
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TBaseViewController.h"
#import "TLocationModel.h"

NS_ASSUME_NONNULL_BEGIN

typedef void(^TSelectLocationDataCompletionBlock)(TLocationModel *model);

@interface TSelectLocationDataViewController : TBaseViewController

@end

NS_ASSUME_NONNULL_END


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.m
================================================
//
//  TSelectLocationDataViewController.m
//  TLocationPlugin
//
//  Created by TBD on 2019/9/4.
//  Copyright © 2019 TBD. All rights reserved.
//

#import "TSelectLocationDataViewController.h"
#import "TLocationNavigationController.h"
#import "TAddLocationDataViewController.h"
#import "TLocationSettingViewController.h"
#import "TLocationTableViewCell.h"
#import "TLocationManager.h"
#import "TAlertController.h"
#import "UIImage+TLocationPlugin.h"
#import "UITableView+TLocationPlugin.h"
#import "UIWindow+TLocationPluginToast.h"

static NSString * const TSelectLocationDataTableViewCellID = @"TSelectLocationDataTableViewCellID";

@interface TSelectLocationDataViewController () <UITableViewDelegate, UITableViewDataSource>

@property (strong, nonatomic) IBOutlet UITableView      *tableView;
@property (nonatomic, assign) BOOL                      hasChangedLocationData;

@property (nonatomic, copy) NSArray<TLocationModel *>   *tableViewData;
@property (nonatomic, assign) NSUInteger                lastSavedCacheDataArrayHash;
@property (nonatomic, readonly, nullable) NSIndexPath   *currentSelectIndex;
@property (nonatomic, strong) TLocationModel            *selectedModel;

@property (nonatomic, copy) NSArray<UIBarButtonItem *>  *leftBarButtonItems;
@property (nonatomic, copy) NSArray<UIBarButtonItem *>  *rightBarButtonItems;

@end

@implementation TSelectLocationDataViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"选择位置";
    UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithImage:[UIImage t_imageNamed:@"close"]
                                                                  style:UIBarButtonItemStylePlain
                                                                 target:self
                                                                 action:@selector(closeSetLocationViewController)];
    
    UIBarButtonItem *settingItem = [[UIBarButtonItem alloc] initWithImage:[UIImage t_imageNamed:@"setting"]
                                                                    style:UIBarButtonItemStylePlain
                                                                   target:self
                                                                   action:@selector(openLocationSettingViewController)];
    UIBarButtonItem *sortItem = [[UIBarButtonItem alloc] initWithTitle:@"编辑"
                                                                 style:UIBarButtonItemStylePlain
                                                                target:self
                                                                action:@selector(editTableView)];
    self.leftBarButtonItems = @[closeItem];
    self.rightBarButtonItems = @[settingItem, sortItem];
    self.navigationItem.leftBarButtonItems = self.leftBarButtonItems;
    self.navigationItem.rightBarButtonItems = self.rightBarButtonItems;
    
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    self.tableView.allowsMultipleSelectionDuringEditing = YES;
    self.lastSavedCacheDataArrayHash = TLocationManager.shared.cacheDataArrayHash;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self refreshTableView];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self storageCacheDataArray];
}

- (NSArray<TLocationModel *> *)tableViewData {
    return TLocationManager.shared.cacheDataArray;
}

- (void)setTableViewData:(NSArray<TLocationModel *> *)tableViewData {
    TLocationManager.shared.cacheDataArray = tableViewData;
}

- (NSIndexPath *)currentSelectIndex {
    __block NSIndexPath *index = nil;
    [self.tableViewData enumerateObjectsUsingBlock:^(TLocationModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if (obj.isSelect) {
            index = [NSIndexPath indexPathForRow:idx inSection:0];
            *stop = YES;
        }
    }];
    return index;
}

- (void)refreshTableView {
    [self.tableView reloadData];
    if (self.currentSelectIndex) {
        [self.tableView selectRowAtIndexPath:self.currentSelectIndex
                                    animated:YES
                              scrollPosition:UITableViewScrollPositionNone];
    }
}

- (void)closeSetLocationViewController {
    [self.view endEditing:YES];
    [self storageCacheDataArray];
    
    /// 修改了数据但是没有启用
    if (self.hasChangedLocationData && !TLocationManager.shared.usingHookLocation) {
        TAlertController *alert = [TAlertController confirmAlertWithTitle:@"是否启用位置拦截?" message:nil cancelTitle:@"否" cancelBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
            [self dismissSelf];
        } confirmTitle:@"是" confirmBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
            TLocationManager.shared.usingHookLocation = YES;
            [self dismissSelf];
        }];
        [alert reverseActions];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }

    [self dismissSelf];
}

- (void)editTableView {
    if (self.tableView.isEditing || self.tableView.isEditBegining) {
        return;
    }
    [self.tableView setEditing:YES animated:YES];
    UIBarButtonItem *deleteItem = [[UIBarButtonItem alloc] initWithTitle:@"删除"
                                                                   style:UIBarButtonItemStylePlain
                                                                  target:self
                                                                  action:@selector(removeTableViewCell)];
    self.navigationItem.leftBarButtonItems = @[deleteItem];
    UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithTitle:@"完成"
                                                                 style:UIBarButtonItemStylePlain
                                                                target:self
                                                                action:@selector(doneEditTableView)];
    self.navigationItem.rightBarButtonItems = @[doneItem];
}

- (void)removeTableViewCell {
    if (self.tableView.indexPathsForSelectedRows.count == 0) {
        return;
    }
    NSMutableArray<TLocationModel *> *tableViewDataArray = [self.tableViewData mutableCopy];
    NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
    [self.tableView.indexPathsForSelectedRows enumerateObjectsUsingBlock:^(NSIndexPath * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [indexSet addIndex:obj.row];
    }];
    [tableViewDataArray removeObjectsAtIndexes:indexSet];
    self.tableViewData = tableViewDataArray;
    [self storageCacheDataArray];
    [self.tableView deleteRowsAtIndexPaths:self.tableView.indexPathsForSelectedRows
                          withRowAnimation:UITableViewRowAnimationLeft];
}

- (void)doneEditTableView {
    if (!self.tableView.isEditing || self.tableView.isEditEnding) {
        return;
    }
    [self.tableView setEditing:NO animated:YES];
    self.navigationItem.leftBarButtonItems = self.leftBarButtonItems;
    self.navigationItem.rightBarButtonItems = self.rightBarButtonItems;
}

- (void)openLocationSettingViewController {
    [self doneEditTableView];
    TLocationSettingViewController *vc = [[TLocationSettingViewController alloc] init];
    [self.navigationController pushViewController:vc animated:YES];
}

- (void)storageCacheDataArray {
    if (self.lastSavedCacheDataArrayHash == TLocationManager.shared.cacheDataArrayHash) {
        return;
    }
    [TLocationManager.shared saveCacheDataArray];
    self.lastSavedCacheDataArrayHash = TLocationManager.shared.cacheDataArrayHash;
}

- (void)storageLocation:(TLocationModel * _Nonnull)model {
    if (model == nil) {
        return;
    }
    self.hasChangedLocationData = YES;
    TLocationManager.shared.locationName = model.name;
    TLocationManager.shared.latitude = model.latitude;
    TLocationManager.shared.longitude = model.longitude;
}

- (void)dismissSelf {
    [self dismissViewControllerAnimated:YES completion:^{
        TLocationNavigationController.isShowing = NO;
    }];
}

- (IBAction)addLocationData:(UIButton *)sender {
    [self doneEditTableView];
    TAddLocationDataViewController *vc = [[TAddLocationDataViewController alloc] init];
    vc.addLocationBlock = ^(TLocationModel * _Nonnull model) {
        NSMutableArray<TLocationModel *> *newDataArray = [self.tableViewData mutableCopy];
        if (newDataArray == nil) {
            newDataArray = [NSMutableArray<TLocationModel *> array];
        }
        [newDataArray insertObject:model atIndex:0];
        self.tableViewData = newDataArray;
        [self storageCacheDataArray];
    };
    [self.navigationController pushViewController:vc animated:YES];
}

#pragma mark - UITableViewDelegate, UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableViewData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TLocationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:TSelectLocationDataTableViewCellID];
    if (cell == nil) {
        cell = [[TLocationTableViewCell alloc] initWithReuseIdentifier:TSelectLocationDataTableViewCellID];
        cell.tableView = tableView;
    }
    TLocationModel *model = self.tableViewData[indexPath.row];
    if (model.isSelect) {
        self.selectedModel = self.tableViewData[indexPath.row];
    }
    cell.model = model;
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (tableView.isEditing) {
        return;
    }
    
    NSMutableArray<NSIndexPath *> *reloadIndexPaths = [NSMutableArray<NSIndexPath *> array];
    [reloadIndexPaths addObject:indexPath];
    
    NSUInteger oldIndex = [self.tableViewData indexOfObject:self.selectedModel];
    if (oldIndex != NSNotFound) {
        NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:oldIndex inSection:0];
        [reloadIndexPaths addObject:oldIndexPath];
    }
    self.selectedModel.isSelect = NO;
    self.selectedModel = self.tableViewData[indexPath.row];
    self.selectedModel.isSelect = YES;
    [self.tableView reloadRowsAtIndexPaths:reloadIndexPaths
                          withRowAnimation:UITableViewRowAnimationNone];
    
    [self storageLocation:self.selectedModel];
    [self storageCacheDataArray];
    
    NSString *toastText = [NSString stringWithFormat:@"已保存为: %@\n%@", self.selectedModel.name, self.selectedModel.locationText];
    [UIWindow t_showTostForMessage:toastText];
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    if (sourceIndexPath.row == destinationIndexPath.row) {
        return;
    }
    NSMutableArray<TLocationModel *> *tableViewDataArray = [self.tableViewData mutableCopy];
    TLocationModel *model = [tableViewDataArray objectAtIndex:sourceIndexPath.row];
    [tableViewDataArray removeObjectAtIndex:sourceIndexPath.row];
    [tableViewDataArray insertObject:model atIndex:destinationIndexPath.row];
    self.tableViewData = tableViewDataArray;
    [self storageCacheDataArray];
}


- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewRowAction *deleleteBtn = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive
                                                                           title:@"删除"
                                                                         handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        [self removeTableViewDataInIndexPath:indexPath];
    }];

    UITableViewRowAction *editBtn = [UITableViewRowAction  rowActionWithStyle:UITableViewRowActionStyleNormal
                                                                        title:@"编辑"
                                                                      handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        [self editTableViewDataInIndexPath:indexPath];
    }];

    UITableViewRowAction *topBtn = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal
                                                                      title:@"置顶"
                                                                    handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        [self topTableViewDataInIndexPath:indexPath];
    }];

    deleleteBtn.backgroundColor = UIColor.redColor;
    editBtn.backgroundColor = UIColor.grayColor;
    topBtn.backgroundColor = UIColor.blackColor;
    return @[deleleteBtn, editBtn, topBtn];
}


#pragma mark - 辅助函数
- (void)topTableViewDataInIndexPath:(NSIndexPath *)indexPath {
    NSIndexPath *firstIndexPath = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
    [self.tableView moveRowAtIndexPath:indexPath toIndexPath:firstIndexPath];

    NSMutableArray<TLocationModel *> *tableViewDataArray = [self.tableViewData mutableCopy];
    TLocationModel *model = [tableViewDataArray objectAtIndex:indexPath.row];
    [tableViewDataArray removeObjectAtIndex:indexPath.row];
    [tableViewDataArray insertObject:model atIndex:0];
    self.tableViewData = tableViewDataArray;
    [self storageCacheDataArray];
}

- (void)removeTableViewDataInIndexPath:(NSIndexPath *)indexPath {
    TLocationModel *model = self.tableViewData[indexPath.row];
    TAlertController *alert = [TAlertController destructiveAlertWithTitle:@"确定删除数据?"
                                                                  message:model.name
                                                              cancelTitle:@"取消"
                                                              cancelBlock:nil
                                                         destructiveTitle:@"确定"
                                                         destructiveBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
        NSMutableArray<TLocationModel *> *tableViewDataArray = [self.tableViewData mutableCopy];
        [tableViewDataArray removeObjectAtIndex:indexPath.row];
        self.tableViewData = tableViewDataArray;
        [self storageCacheDataArray];
        [self.tableView deleteRowsAtIndexPaths:@[indexPath]
                              withRowAnimation:UITableViewRowAnimationLeft];
    }];
    [self presentViewController:alert animated:YES completion:nil];
}

- (void)editTableViewDataInIndexPath:(NSIndexPath *)indexPath {
    if (indexPath == nil) {
        return;
    }
    TLocationModel *model = self.tableViewData[indexPath.row];
    TAlertController *alert = [TAlertController editAlertWithTitle:@"修改数据"
                                                           message:model.name
                                                        labelTexts:@[@"名称", @"纬度", @"经度"]
                                                     defaultValues:@[
                                                         model.name ?: @"",
                                                         @(model.latitude).stringValue,
                                                         @(model.longitude).stringValue,
                                                     ]
                                                       cancelTitle:@"取消"
                                                       cancelBlock:nil
                                                      confirmTitle:@"确定"
                                                      confirmBlock:^(TAlertController * _Nonnull alert, UIAlertAction * _Nonnull action) {
        model.name = alert.textFields[0].text;
        model.latitude = alert.textFields[1].text.doubleValue;
        model.longitude = alert.textFields[2].text.doubleValue;
        if (model.isSelect) {
            [self storageLocation:model];
        }
        [self storageCacheDataArray];
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
    }];
    [self presentViewController:alert animated:YES completion:nil];
}

@end


================================================
FILE: TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.xib
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
    <device id="retina5_9" orientation="portrait" appearance="light"/>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <o
Download .txt
gitextract_c9p7_8y9/

├── .gitignore
├── README.md
├── RunScript/
│   ├── build_all.sh
│   ├── devices_arm_info.sh
│   ├── env.sh
│   ├── inject.sh
│   └── inject_app_icon.py
├── TLocationPlugin/
│   ├── Info.plist
│   ├── NSObject+TLocationPlugin.h
│   ├── NSObject+TLocationPlugin.m
│   ├── Others/
│   │   ├── TLocationManager.h
│   │   ├── TLocationManager.m
│   │   ├── TLocationModel.h
│   │   ├── TLocationModel.m
│   │   ├── TLocationPluginLocationConverter.h
│   │   └── TLocationPluginLocationConverter.m
│   ├── TLocationPlugin.h
│   ├── TSafeRuntimeCFunc.h
│   ├── TSafeRuntimeCFunc.m
│   ├── Tools/
│   │   ├── CALayer+TLocationPlugin.h
│   │   ├── CALayer+TLocationPlugin.m
│   │   ├── NSBundle+TLocationPlugin.h
│   │   ├── NSBundle+TLocationPlugin.m
│   │   ├── TAlertController.h
│   │   ├── TAlertController.m
│   │   ├── TLocationDefine.h
│   │   ├── UIApplication+TLocationPlugin.h
│   │   ├── UIApplication+TLocationPlugin.m
│   │   ├── UIImage+TLocationPlugin.h
│   │   ├── UIImage+TLocationPlugin.m
│   │   ├── UITableView+TLocationPlugin.h
│   │   ├── UITableView+TLocationPlugin.m
│   │   ├── UIViewController+TLocationPlugin.h
│   │   ├── UIViewController+TLocationPlugin.m
│   │   ├── UIWindow+TLocationPluginToast.h
│   │   ├── UIWindow+TLocationPluginToast.m
│   │   ├── UIWindow+TLocationPluginTouch.h
│   │   └── UIWindow+TLocationPluginTouch.m
│   └── ViewControllerAndViews/
│       ├── TAddLocationDataViewController.h
│       ├── TAddLocationDataViewController.m
│       ├── TAddLocationDataViewController.xib
│       ├── TBaseViewController.h
│       ├── TBaseViewController.m
│       ├── TLocationChangeAppICONViewController.h
│       ├── TLocationChangeAppICONViewController.m
│       ├── TLocationChangeAppICONViewController.xib
│       ├── TLocationNavigationController.h
│       ├── TLocationNavigationController.m
│       ├── TLocationSettingViewController.h
│       ├── TLocationSettingViewController.m
│       ├── TLocationSettingViewController.xib
│       ├── TLocationTableViewCell.h
│       ├── TLocationTableViewCell.m
│       ├── TSelectLocationDataViewController.h
│       ├── TSelectLocationDataViewController.m
│       └── TSelectLocationDataViewController.xib
├── TLocationPlugin.xcodeproj/
│   ├── project.pbxproj
│   ├── project.xcworkspace/
│   │   ├── contents.xcworkspacedata
│   │   └── xcshareddata/
│   │       └── IDEWorkspaceChecks.plist
│   └── xcshareddata/
│       └── xcschemes/
│           ├── TLocationPlugin.xcscheme
│           └── TestLocationPlugin.xcscheme
├── TestLocationPlugin/
│   ├── AppDelegate.h
│   ├── AppDelegate.m
│   ├── Assets.xcassets/
│   │   ├── AppIcon.appiconset/
│   │   │   └── Contents.json
│   │   └── Contents.json
│   ├── Base.lproj/
│   │   ├── LaunchScreen.storyboard
│   │   └── Main.storyboard
│   ├── Info.plist
│   ├── ViewController.h
│   ├── ViewController.m
│   └── main.m
├── requirements.txt
└── yololib/
    ├── README.md
    ├── main.m
    └── yololib.xcodeproj/
        ├── project.pbxproj
        └── project.xcworkspace/
            ├── contents.xcworkspacedata
            └── xcshareddata/
                └── IDEWorkspaceChecks.plist
Download .txt
SYMBOL INDEX (12 symbols across 1 files)

FILE: RunScript/inject_app_icon.py
  function read_plist (line 17) | def read_plist(path):
  function write_plist (line 20) | def write_plist(info, path):
  function read_plist (line 25) | def read_plist(path):
  function write_plist (line 29) | def write_plist(info, path):
  function convertImage (line 61) | def convertImage(imageFile, outdir, size, scale, is_iPhone):
  function createCFBundleIconFiles (line 82) | def createCFBundleIconFiles(name, is_iPhone):
  function createCFBundleAlternateIconSingle (line 96) | def createCFBundleAlternateIconSingle(name, is_iPhone):
  function createPrimaryIconInfo (line 103) | def createPrimaryIconInfo(primaryIconName, is_iPhone):
  function createCFBundleAlternateIcons (line 111) | def createCFBundleAlternateIcons(names, is_iPhone):
  function createNewIconInfo (line 121) | def createNewIconInfo(names, newPrimaryIcon, oldPrimaryInfo, is_iPhone):
  function moveIconsToDirectory (line 134) | def moveIconsToDirectory(origin_dir_path, dest_dir_path):
  function setIcon (line 142) | def setIcon(plist_info, newIconNames, newPrimaryIcon, is_iPhone):
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (367K chars).
[
  {
    "path": ".gitignore",
    "chars": 2935,
    "preview": "#########################\n# .gitignore file for Xcode4 / OS X Source projects\n#\n# NB: if you are storing \"built\" product"
  },
  {
    "path": "README.md",
    "chars": 1253,
    "preview": "### TLocationPlugin\n\n> iOS 版本企业微信等软件虚拟定位,仅为个人学习 hook 以及移植非越狱手机实验(防hook 以及验证签名的App没有针对性处理)\n\n### 功能\n\n- [x] 设置定位信息\n\n- [x] 保"
  },
  {
    "path": "RunScript/build_all.sh",
    "chars": 2235,
    "preview": "#!/usr/bin/env zsh --login\n\nset -ex\n\nCUR_DIR=$(realpath $(dirname \"$0\"))\n\nsource \"$CUR_DIR/env.sh\"\n\nUNIVERSAL_OUTPUTFOLD"
  },
  {
    "path": "RunScript/devices_arm_info.sh",
    "chars": 1137,
    "preview": "#!/usr/bin/env zsh --login\n\n# arm64 Support\nexport ARM64_DEVICES=\\\n'\n\"iPhone6,1\",\n\"iPhone6,2\",\n\"iPhone7,1\",\n\"iPhone7,2\","
  },
  {
    "path": "RunScript/env.sh",
    "chars": 387,
    "preview": "#!/usr/bin/env zsh --login\n\n# Base Dir\nBASEDIR=$(realpath \"${PROJECT_DIR}\")\n\n# 注入 framework 名称\nexport FRAMEWORK_NAME=\"TL"
  },
  {
    "path": "RunScript/inject.sh",
    "chars": 1563,
    "preview": "#!/usr/bin/env zsh --login\n\nset -ex\n\nCUR_DIR=$(realpath $(dirname \"$0\"))\n\nsource \"$CUR_DIR/devices_arm_info.sh\"\nsource \""
  },
  {
    "path": "RunScript/inject_app_icon.py",
    "chars": 6337,
    "preview": "# /usr/local/bin/python3\n# -*- coding: utf-8 -*-\n\nimport os\nimport sys\nimport glob\nimport shutil\nimport pprint\n\nfrom PIL"
  },
  {
    "path": "TLocationPlugin/Info.plist",
    "chars": 752,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "TLocationPlugin/NSObject+TLocationPlugin.h",
    "chars": 256,
    "preview": "//\n//  NSObject+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All r"
  },
  {
    "path": "TLocationPlugin/NSObject+TLocationPlugin.m",
    "chars": 5655,
    "preview": "//\n//  NSObject+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All r"
  },
  {
    "path": "TLocationPlugin/Others/TLocationManager.h",
    "chars": 1656,
    "preview": "//\n//  TLocationManager.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All rights re"
  },
  {
    "path": "TLocationPlugin/Others/TLocationManager.m",
    "chars": 9558,
    "preview": "//\n//  TLocationManager.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All rights re"
  },
  {
    "path": "TLocationPlugin/Others/TLocationModel.h",
    "chars": 1014,
    "preview": "//\n//  TLocationModel.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All rights rese"
  },
  {
    "path": "TLocationPlugin/Others/TLocationModel.m",
    "chars": 2781,
    "preview": "//\n//  TLocationModel.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All rights rese"
  },
  {
    "path": "TLocationPlugin/Others/TLocationPluginLocationConverter.h",
    "chars": 1548,
    "preview": "//\n//  JZLocationConverter.h\n//  JZCLLocationMangerDome\n//\n//  Created by jack zhou on 13-8-22.\n//  Copyright (c) 2013年 "
  },
  {
    "path": "TLocationPlugin/Others/TLocationPluginLocationConverter.m",
    "chars": 4958,
    "preview": "//\n//  JZLocationConverter.m\n//  JZCLLocationMangerDome\n//\n//  Created by jack zhou on 13-8-22.\n//  Copyright (c) 2013年 "
  },
  {
    "path": "TLocationPlugin/TLocationPlugin.h",
    "chars": 530,
    "preview": "//\n//  TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. All rights res"
  },
  {
    "path": "TLocationPlugin/TSafeRuntimeCFunc.h",
    "chars": 773,
    "preview": "//\n//  TSafeRuntimeCFunc.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2018/4/19.\n//  Copyright © 2019 TBD. All rights "
  },
  {
    "path": "TLocationPlugin/TSafeRuntimeCFunc.m",
    "chars": 2137,
    "preview": "//\n//  TSafeRuntimeCFunc.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2018/4/19.\n//  Copyright © 2019 TBD. All rights "
  },
  {
    "path": "TLocationPlugin/Tools/CALayer+TLocationPlugin.h",
    "chars": 356,
    "preview": "//\n//  CALayer+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/6.\n//  Copyright © 2019 TBD. All ri"
  },
  {
    "path": "TLocationPlugin/Tools/CALayer+TLocationPlugin.m",
    "chars": 421,
    "preview": "//\n//  CALayer+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/6.\n//  Copyright © 2019 TBD. All ri"
  },
  {
    "path": "TLocationPlugin/Tools/NSBundle+TLocationPlugin.h",
    "chars": 294,
    "preview": "//\n//  NSBundle+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All r"
  },
  {
    "path": "TLocationPlugin/Tools/NSBundle+TLocationPlugin.m",
    "chars": 790,
    "preview": "//\n//  NSBundle+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All r"
  },
  {
    "path": "TLocationPlugin/Tools/TAlertController.h",
    "chars": 2431,
    "preview": "//\n//  TAlertController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/6.\n//  Copyright © 2019 TBD. All rights re"
  },
  {
    "path": "TLocationPlugin/Tools/TAlertController.m",
    "chars": 9328,
    "preview": "//\n//  TAlertController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/6.\n//  Copyright © 2019 TBD. All rights re"
  },
  {
    "path": "TLocationPlugin/Tools/TLocationDefine.h",
    "chars": 1423,
    "preview": "//\n//  TLocationDefine.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/6.\n//  Copyright © 2019 TBD. All rights res"
  },
  {
    "path": "TLocationPlugin/Tools/UIApplication+TLocationPlugin.h",
    "chars": 375,
    "preview": "//\n//  UIApplication+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/Tools/UIApplication+TLocationPlugin.m",
    "chars": 548,
    "preview": "//\n//  UIApplication+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/Tools/UIImage+TLocationPlugin.h",
    "chars": 433,
    "preview": "//\n//  UIImage+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All ri"
  },
  {
    "path": "TLocationPlugin/Tools/UIImage+TLocationPlugin.m",
    "chars": 1382,
    "preview": "//\n//  UIImage+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All ri"
  },
  {
    "path": "TLocationPlugin/Tools/UITableView+TLocationPlugin.h",
    "chars": 404,
    "preview": "//\n//  UITableView+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TBD. Al"
  },
  {
    "path": "TLocationPlugin/Tools/UITableView+TLocationPlugin.m",
    "chars": 1410,
    "preview": "//\n//  UITableView+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TBD. Al"
  },
  {
    "path": "TLocationPlugin/Tools/UIViewController+TLocationPlugin.h",
    "chars": 522,
    "preview": "//\n//  UIViewController+TLocationPlugin.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TB"
  },
  {
    "path": "TLocationPlugin/Tools/UIViewController+TLocationPlugin.m",
    "chars": 2289,
    "preview": "//\n//  UIViewController+TLocationPlugin.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/8.\n//  Copyright © 2019 TB"
  },
  {
    "path": "TLocationPlugin/Tools/UIWindow+TLocationPluginToast.h",
    "chars": 559,
    "preview": "//\n//  UIWindow+TLocationPluginToast.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/Tools/UIWindow+TLocationPluginToast.m",
    "chars": 4274,
    "preview": "//\n//  UIWindow+TLocationPluginToast.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/Tools/UIWindow+TLocationPluginTouch.h",
    "chars": 267,
    "preview": "//\n//  UIWindow+TLocationPluginTouch.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/Tools/UIWindow+TLocationPluginTouch.m",
    "chars": 1603,
    "preview": "//\n//  UIWindow+TLocationPluginTouch.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.h",
    "chars": 499,
    "preview": "//\n//  TAddLocationDataViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD."
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.m",
    "chars": 14617,
    "preview": "//\n//  TAddLocationDataViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD."
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TAddLocationDataViewController.xib",
    "chars": 12791,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TBaseViewController.h",
    "chars": 264,
    "preview": "//\n//  TBaseViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TBaseViewController.m",
    "chars": 698,
    "preview": "//\n//  TBaseViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.h",
    "chars": 332,
    "preview": "//\n//  TLocationChangeAppICONViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/9.\n//  Copyright © 201"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.m",
    "chars": 2082,
    "preview": "//\n//  TLocationChangeAppICONViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/9.\n//  Copyright © 201"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationChangeAppICONViewController.xib",
    "chars": 19879,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationNavigationController.h",
    "chars": 343,
    "preview": "//\n//  TLocationNavigationController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationNavigationController.m",
    "chars": 1724,
    "preview": "//\n//  TLocationNavigationController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. "
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.h",
    "chars": 321,
    "preview": "//\n//  TLocationSettingViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD."
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.m",
    "chars": 4512,
    "preview": "//\n//  TLocationSettingViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 TBD."
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.xib",
    "chars": 36405,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationTableViewCell.h",
    "chars": 513,
    "preview": "//\n//  TLocationTableViewCell.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rig"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TLocationTableViewCell.m",
    "chars": 1855,
    "preview": "//\n//  TLocationTableViewCell.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rig"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.h",
    "chars": 429,
    "preview": "//\n//  TSelectLocationDataViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 T"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.m",
    "chars": 16743,
    "preview": "//\n//  TSelectLocationDataViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/4.\n//  Copyright © 2019 T"
  },
  {
    "path": "TLocationPlugin/ViewControllerAndViews/TSelectLocationDataViewController.xib",
    "chars": 6573,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVe"
  },
  {
    "path": "TLocationPlugin.xcodeproj/project.pbxproj",
    "chars": 105480,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXAggregateTarget sec"
  },
  {
    "path": "TLocationPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 135,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef"
  },
  {
    "path": "TLocationPlugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "TLocationPlugin.xcodeproj/xcshareddata/xcschemes/TLocationPlugin.xcscheme",
    "chars": 2429,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1130\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "TLocationPlugin.xcodeproj/xcshareddata/xcschemes/TestLocationPlugin.xcscheme",
    "chars": 2888,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1130\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "TestLocationPlugin/AppDelegate.h",
    "chars": 270,
    "preview": "//\n//  AppDelegate.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights reserve"
  },
  {
    "path": "TestLocationPlugin/AppDelegate.m",
    "chars": 2032,
    "preview": "//\n//  AppDelegate.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights reserve"
  },
  {
    "path": "TestLocationPlugin/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 1590,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\""
  },
  {
    "path": "TestLocationPlugin/Assets.xcassets/Contents.json",
    "chars": 62,
    "preview": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "TestLocationPlugin/Base.lproj/LaunchScreen.storyboard",
    "chars": 1658,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "TestLocationPlugin/Base.lproj/Main.storyboard",
    "chars": 1591,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
  },
  {
    "path": "TestLocationPlugin/Info.plist",
    "chars": 6218,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "TestLocationPlugin/ViewController.h",
    "chars": 208,
    "preview": "//\n//  ViewController.h\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights rese"
  },
  {
    "path": "TestLocationPlugin/ViewController.m",
    "chars": 287,
    "preview": "//\n//  ViewController.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights rese"
  },
  {
    "path": "TestLocationPlugin/main.m",
    "chars": 327,
    "preview": "//\n//  main.m\n//  TLocationPlugin\n//\n//  Created by TBD on 2019/9/5.\n//  Copyright © 2019 TBD. All rights reserved.\n//\n\n"
  },
  {
    "path": "requirements.txt",
    "chars": 15,
    "preview": "biplist\nPillow\n"
  },
  {
    "path": "yololib/README.md",
    "chars": 125,
    "preview": "yololib\n=======\n\ndylib injector for mach-o binaries\n\n\nUsage\n============\n\nSelf-explainatory\n\n`yololib` `binary` `dylib f"
  },
  {
    "path": "yololib/main.m",
    "chars": 6713,
    "preview": "/*\n yololib\n Inject dylibs into existing Mach-O binaries\n \n \n DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n Version 2, De"
  },
  {
    "path": "yololib/yololib.xcodeproj/project.pbxproj",
    "chars": 8970,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "yololib/yololib.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 152,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:yololib.xcodepr"
  },
  {
    "path": "yololib/yololib.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  }
]

About this extraction

This page contains the full source code of the ToBeDefined/TLocationPlugin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (330.8 KB), approximately 99.3k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!