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),会打开定位设置界面
## 示例
- 设置定位界面
- 添加位置界面
- 设置界面
- 使用界面
================================================
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
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
================================================
FILE: TLocationPlugin/NSObject+TLocationPlugin.h
================================================
//
// NSObject+TLocationPlugin.h
// TLocationPlugin
//
// Created by TBD on 2019/9/4.
// Copyright © 2019 TBD. All rights reserved.
//
#import
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
#import "NSObject+TLocationPlugin.h"
#import "TSafeRuntimeCFunc.h"
#import "TLocationManager.h"
#import "UIWindow+TLocationPluginToast.h"
#import
#import
@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 *)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 *t_locations = [NSMutableArray 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 *)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
#import
#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 *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 * _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 *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirPath = [paths lastObject];
_t_cacheDataArrayArchivePath = [documentDirPath stringByAppendingPathComponent:@"_T_CacheKeyTypeDataArray.archiver"];
});
return _t_cacheDataArrayArchivePath;
}
- (NSArray *)cacheDataArray {
return self->_cacheDataArray;
}
- (void)setCacheDataArray:(NSArray *)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
#import
NS_ASSUME_NONNULL_BEGIN
@interface TLocationModel : NSObject
/// 名称
@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
#import
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
#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
//! 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
================================================
FILE: TLocationPlugin/TSafeRuntimeCFunc.h
================================================
//
// TSafeRuntimeCFunc.h
// TLocationPlugin
//
// Created by TBD on 2018/4/19.
// Copyright © 2019 TBD. All rights reserved.
//
#import
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
#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
#import
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
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
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 *)labelTexts
defaultValues:(nullable NSArray *)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 ()
@property (nonatomic, assign) BOOL isLoaded;
@property (nonatomic, strong) UIAlertAction *confirmAction;
@property (nonatomic, copy) TAlertControllerBlock confirmBlock;
@property (nonatomic, strong) NSMutableArray *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 *)labelTexts
defaultValues:(nullable NSArray *)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 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 *)mutableActions {
if (self->_mutableActions == nil) {
self->_mutableActions = [NSMutableArray 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
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
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
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
@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
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
#import
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 *)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 *)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
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
#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 *)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
#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
#import
#import "TAddLocationDataViewController.h"
#import "TLocationTableViewCell.h"
#import "TAlertController.h"
#import "UIImage+TLocationPlugin.h"
#import "UIWindow+TLocationPluginToast.h"
typedef void (^GetPlaceInfoBlock)(NSArray *_Nullable models);
typedef NS_ENUM(NSUInteger, TMapViewAnnotationType) {
TMapViewAnnotationTypeFirst,
TMapViewAnnotationTypeAll,
};
static NSString * const TAddLocationDataTableViewCellID = @"TAddLocationDataTableViewCellID";
@interface TAddLocationDataViewController ()
@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 *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 *)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 *)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 * _Nullable placemarks, NSError * _Nullable error) {
if (placemarks == nil) {
self.tableViewData = nil;
[self.mapView removeAnnotations:self.mapView.annotations];
[self.tableView reloadData];
return;
}
NSMutableArray *locationModelArray = [NSMutableArray 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 *locationModelArray = [NSMutableArray 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 *reloadIndexPaths = [NSMutableArray 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
================================================
================================================
FILE: TLocationPlugin/ViewControllerAndViews/TBaseViewController.h
================================================
//
// TBaseViewController.h
// TLocationPlugin
//
// Created by TBD on 2019/9/5.
// Copyright © 2019 TBD. All rights reserved.
//
#import
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
#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
================================================
================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationNavigationController.h
================================================
//
// TLocationNavigationController.h
// TLocationPlugin
//
// Created by TBD on 2019/9/5.
// Copyright © 2019 TBD. All rights reserved.
//
#import
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
#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 ()
@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 *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
@end
================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationSettingViewController.xib
================================================
================================================
FILE: TLocationPlugin/ViewControllerAndViews/TLocationTableViewCell.h
================================================
//
// TLocationTableViewCell.h
// TLocationPlugin
//
// Created by TBD on 2019/9/5.
// Copyright © 2019 TBD. All rights reserved.
//
#import
#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
#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 ()
@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, assign) BOOL hasChangedLocationData;
@property (nonatomic, copy) NSArray *tableViewData;
@property (nonatomic, assign) NSUInteger lastSavedCacheDataArrayHash;
@property (nonatomic, readonly, nullable) NSIndexPath *currentSelectIndex;
@property (nonatomic, strong) TLocationModel *selectedModel;
@property (nonatomic, copy) NSArray *leftBarButtonItems;
@property (nonatomic, copy) NSArray *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 *)tableViewData {
return TLocationManager.shared.cacheDataArray;
}
- (void)setTableViewData:(NSArray *)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 *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 *newDataArray = [self.tableViewData mutableCopy];
if (newDataArray == nil) {
newDataArray = [NSMutableArray 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 *reloadIndexPaths = [NSMutableArray 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 *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 *)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 *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 *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
================================================
================================================
FILE: TLocationPlugin.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXAggregateTarget section */
3F9CDAA62321F26D000E7A24 /* RunScript */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 3F9CDAA72321F26D000E7A24 /* Build configuration list for PBXAggregateTarget "RunScript" */;
buildPhases = (
3F9CDAAA2321F275000E7A24 /* BuildFramework */,
3FC34C7D2322524C00C15E66 /* InjectFramework */,
);
dependencies = (
);
name = RunScript;
productName = RunScript;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
3F0A641023217506002FA767 /* CALayer+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F0A640E23217506002FA767 /* CALayer+TLocationPlugin.h */; };
3F0A641123217506002FA767 /* CALayer+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F0A640F23217506002FA767 /* CALayer+TLocationPlugin.m */; };
3F0FE5112320FBFC008B0830 /* TLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F0FE50F2320FBFC008B0830 /* TLocationManager.h */; };
3F0FE5122320FBFC008B0830 /* TLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F0FE5102320FBFC008B0830 /* TLocationManager.m */; };
3F344C0C23227F2F000A0D9F /* TAlertController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F344C0A23227F2F000A0D9F /* TAlertController.h */; };
3F344C0D23227F2F000A0D9F /* TAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F344C0B23227F2F000A0D9F /* TAlertController.m */; };
3F35B14D2325431200E785B9 /* UIApplication+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F35B14B2325431200E785B9 /* UIApplication+TLocationPlugin.h */; };
3F35B14E2325431200E785B9 /* UIApplication+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F35B14C2325431200E785B9 /* UIApplication+TLocationPlugin.m */; };
3F35B1512325436B00E785B9 /* UIViewController+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F35B14F2325436B00E785B9 /* UIViewController+TLocationPlugin.h */; };
3F35B1522325436B00E785B9 /* UIViewController+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F35B1502325436B00E785B9 /* UIViewController+TLocationPlugin.m */; };
3F542A982326225500497668 /* TLocationChangeAppICONViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F542A952326225500497668 /* TLocationChangeAppICONViewController.h */; };
3F542A992326225500497668 /* TLocationChangeAppICONViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F542A962326225500497668 /* TLocationChangeAppICONViewController.m */; };
3F542A9A2326225500497668 /* TLocationChangeAppICONViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3F542A972326225500497668 /* TLocationChangeAppICONViewController.xib */; };
3F56897723262F2100FE42DE /* QQ29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890023262F1B00FE42DE /* QQ29x29@2x.png */; };
3F56897823262F2100FE42DE /* Tim29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890123262F1B00FE42DE /* Tim29x29@2x~ipad.png */; };
3F56897923262F2100FE42DE /* WeChat29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890223262F1B00FE42DE /* WeChat29x29@2x~ipad.png */; };
3F56897A23262F2100FE42DE /* Lark60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890323262F1B00FE42DE /* Lark60x60@3x.png */; };
3F56897B23262F2100FE42DE /* NeiXin60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890423262F1B00FE42DE /* NeiXin60x60@3x.png */; };
3F56897C23262F2100FE42DE /* WeChat76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890523262F1B00FE42DE /* WeChat76x76@2x~ipad.png */; };
3F56897D23262F2100FE42DE /* WeWork20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890623262F1B00FE42DE /* WeWork20x20~ipad.png */; };
3F56897E23262F2100FE42DE /* Tim76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890723262F1B00FE42DE /* Tim76x76@2x~ipad.png */; };
3F56897F23262F2100FE42DE /* DingDing60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890823262F1B00FE42DE /* DingDing60x60@2x.png */; };
3F56898023262F2100FE42DE /* WeWork40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890923262F1B00FE42DE /* WeWork40x40@3x.png */; };
3F56898123262F2100FE42DE /* DingDing20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890A23262F1B00FE42DE /* DingDing20x20@2x~ipad.png */; };
3F56898223262F2100FE42DE /* NeiXin20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890B23262F1B00FE42DE /* NeiXin20x20~ipad.png */; };
3F56898323262F2100FE42DE /* NeiXin20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890C23262F1C00FE42DE /* NeiXin20x20@2x.png */; };
3F56898423262F2100FE42DE /* Lark83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890D23262F1C00FE42DE /* Lark83.5x83.5@2x~ipad.png */; };
3F56898523262F2100FE42DE /* DingDing20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890E23262F1C00FE42DE /* DingDing20x20@3x.png */; };
3F56898623262F2100FE42DE /* NeiXin76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56890F23262F1C00FE42DE /* NeiXin76x76@2x~ipad.png */; };
3F56898723262F2100FE42DE /* Lark76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891023262F1C00FE42DE /* Lark76x76@2x~ipad.png */; };
3F56898823262F2100FE42DE /* QQ20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891123262F1C00FE42DE /* QQ20x20@3x.png */; };
3F56898923262F2100FE42DE /* WeWork29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891223262F1C00FE42DE /* WeWork29x29~ipad.png */; };
3F56898A23262F2100FE42DE /* QQ40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891323262F1C00FE42DE /* QQ40x40@3x.png */; };
3F56898B23262F2100FE42DE /* NeiXin29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891423262F1C00FE42DE /* NeiXin29x29@3x.png */; };
3F56898C23262F2100FE42DE /* WeChat20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891523262F1C00FE42DE /* WeChat20x20~ipad.png */; };
3F56898D23262F2100FE42DE /* NeiXin40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891623262F1C00FE42DE /* NeiXin40x40@2x.png */; };
3F56898E23262F2100FE42DE /* WeWork40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891723262F1C00FE42DE /* WeWork40x40~ipad.png */; };
3F56898F23262F2100FE42DE /* WeWork20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891823262F1C00FE42DE /* WeWork20x20@2x.png */; };
3F56899023262F2100FE42DE /* Lark40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891923262F1C00FE42DE /* Lark40x40@2x~ipad.png */; };
3F56899123262F2100FE42DE /* QQ20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891A23262F1C00FE42DE /* QQ20x20@2x.png */; };
3F56899223262F2100FE42DE /* WeChat29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891B23262F1C00FE42DE /* WeChat29x29~ipad.png */; };
3F56899323262F2100FE42DE /* WeChat20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891C23262F1C00FE42DE /* WeChat20x20@2x~ipad.png */; };
3F56899423262F2100FE42DE /* WeChat40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891D23262F1C00FE42DE /* WeChat40x40~ipad.png */; };
3F56899523262F2100FE42DE /* Tim40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891E23262F1C00FE42DE /* Tim40x40~ipad.png */; };
3F56899623262F2100FE42DE /* WeWork60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56891F23262F1C00FE42DE /* WeWork60x60@2x.png */; };
3F56899723262F2100FE42DE /* Lark60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892023262F1C00FE42DE /* Lark60x60@2x.png */; };
3F56899823262F2100FE42DE /* Lark29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892123262F1C00FE42DE /* Lark29x29@2x.png */; };
3F56899923262F2100FE42DE /* QQ40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892223262F1C00FE42DE /* QQ40x40@2x~ipad.png */; };
3F56899A23262F2100FE42DE /* NeiXin29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892323262F1D00FE42DE /* NeiXin29x29@2x~ipad.png */; };
3F56899B23262F2100FE42DE /* DingDing40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892423262F1D00FE42DE /* DingDing40x40@2x.png */; };
3F56899C23262F2100FE42DE /* WeChat20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892523262F1D00FE42DE /* WeChat20x20@2x.png */; };
3F56899D23262F2100FE42DE /* Lark20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892623262F1D00FE42DE /* Lark20x20@2x.png */; };
3F56899E23262F2100FE42DE /* QQ20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892723262F1D00FE42DE /* QQ20x20@2x~ipad.png */; };
3F56899F23262F2100FE42DE /* NeiXin40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892823262F1D00FE42DE /* NeiXin40x40@3x.png */; };
3F5689A023262F2100FE42DE /* Lark29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892923262F1D00FE42DE /* Lark29x29~ipad.png */; };
3F5689A123262F2100FE42DE /* WeChat60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892A23262F1D00FE42DE /* WeChat60x60@3x.png */; };
3F5689A223262F2100FE42DE /* WeWork40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892B23262F1D00FE42DE /* WeWork40x40@2x.png */; };
3F5689A323262F2100FE42DE /* WeChat76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892C23262F1D00FE42DE /* WeChat76x76~ipad.png */; };
3F5689A423262F2100FE42DE /* WeWork20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892D23262F1D00FE42DE /* WeWork20x20@3x.png */; };
3F5689A523262F2100FE42DE /* Tim76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892E23262F1D00FE42DE /* Tim76x76~ipad.png */; };
3F5689A623262F2100FE42DE /* QQ40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56892F23262F1D00FE42DE /* QQ40x40~ipad.png */; };
3F5689A723262F2100FE42DE /* Tim29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893023262F1D00FE42DE /* Tim29x29@3x.png */; };
3F5689A823262F2100FE42DE /* NeiXin60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893123262F1D00FE42DE /* NeiXin60x60@2x.png */; };
3F5689A923262F2100FE42DE /* DingDing76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893223262F1D00FE42DE /* DingDing76x76~ipad.png */; };
3F5689AA23262F2100FE42DE /* DingDing20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893323262F1D00FE42DE /* DingDing20x20@2x.png */; };
3F5689AB23262F2100FE42DE /* WeWork60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893423262F1D00FE42DE /* WeWork60x60@3x.png */; };
3F5689AC23262F2100FE42DE /* QQ60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893523262F1D00FE42DE /* QQ60x60@2x.png */; };
3F5689AD23262F2100FE42DE /* Lark40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893623262F1D00FE42DE /* Lark40x40@2x.png */; };
3F5689AE23262F2100FE42DE /* Lark29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893723262F1D00FE42DE /* Lark29x29@2x~ipad.png */; };
3F5689AF23262F2100FE42DE /* WeChat29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893823262F1D00FE42DE /* WeChat29x29@3x.png */; };
3F5689B023262F2100FE42DE /* NeiXin40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893923262F1E00FE42DE /* NeiXin40x40@2x~ipad.png */; };
3F5689B123262F2100FE42DE /* Tim20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893A23262F1E00FE42DE /* Tim20x20@3x.png */; };
3F5689B223262F2100FE42DE /* QQ29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893B23262F1E00FE42DE /* QQ29x29@3x.png */; };
3F5689B323262F2100FE42DE /* Tim40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893C23262F1E00FE42DE /* Tim40x40@3x.png */; };
3F5689B423262F2100FE42DE /* Tim60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893D23262F1E00FE42DE /* Tim60x60@2x.png */; };
3F5689B523262F2100FE42DE /* DingDing29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893E23262F1E00FE42DE /* DingDing29x29@2x.png */; };
3F5689B623262F2100FE42DE /* Tim29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56893F23262F1E00FE42DE /* Tim29x29~ipad.png */; };
3F5689B723262F2100FE42DE /* Lark20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894023262F1E00FE42DE /* Lark20x20~ipad.png */; };
3F5689B823262F2100FE42DE /* QQ76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894123262F1E00FE42DE /* QQ76x76@2x~ipad.png */; };
3F5689B923262F2100FE42DE /* WeChat40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894223262F1E00FE42DE /* WeChat40x40@2x~ipad.png */; };
3F5689BA23262F2100FE42DE /* Tim29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894323262F1E00FE42DE /* Tim29x29@2x.png */; };
3F5689BB23262F2100FE42DE /* DingDing60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894423262F1E00FE42DE /* DingDing60x60@3x.png */; };
3F5689BC23262F2100FE42DE /* WeChat40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894523262F1E00FE42DE /* WeChat40x40@3x.png */; };
3F5689BD23262F2100FE42DE /* WeWork29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894623262F1E00FE42DE /* WeWork29x29@2x.png */; };
3F5689BE23262F2100FE42DE /* Tim83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894723262F1E00FE42DE /* Tim83.5x83.5@2x~ipad.png */; };
3F5689BF23262F2100FE42DE /* NeiXin83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894823262F1E00FE42DE /* NeiXin83.5x83.5@2x~ipad.png */; };
3F5689C023262F2100FE42DE /* DingDing40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894923262F1E00FE42DE /* DingDing40x40~ipad.png */; };
3F5689C123262F2100FE42DE /* Tim40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894A23262F1E00FE42DE /* Tim40x40@2x~ipad.png */; };
3F5689C223262F2100FE42DE /* DingDing83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894B23262F1E00FE42DE /* DingDing83.5x83.5@2x~ipad.png */; };
3F5689C323262F2100FE42DE /* QQ29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894C23262F1E00FE42DE /* QQ29x29~ipad.png */; };
3F5689C423262F2100FE42DE /* Lark40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894D23262F1E00FE42DE /* Lark40x40~ipad.png */; };
3F5689C523262F2100FE42DE /* NeiXin20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894E23262F1E00FE42DE /* NeiXin20x20@3x.png */; };
3F5689C623262F2100FE42DE /* NeiXin20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56894F23262F1E00FE42DE /* NeiXin20x20@2x~ipad.png */; };
3F5689C723262F2100FE42DE /* NeiXin76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895023262F1E00FE42DE /* NeiXin76x76~ipad.png */; };
3F5689C823262F2100FE42DE /* WeWork76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895123262F1F00FE42DE /* WeWork76x76@2x~ipad.png */; };
3F5689C923262F2100FE42DE /* Lark20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895223262F1F00FE42DE /* Lark20x20@2x~ipad.png */; };
3F5689CA23262F2100FE42DE /* NeiXin29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895323262F1F00FE42DE /* NeiXin29x29@2x.png */; };
3F5689CB23262F2200FE42DE /* DingDing29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895423262F1F00FE42DE /* DingDing29x29@2x~ipad.png */; };
3F5689CC23262F2200FE42DE /* NeiXin29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895523262F1F00FE42DE /* NeiXin29x29~ipad.png */; };
3F5689CD23262F2200FE42DE /* WeWork29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895623262F1F00FE42DE /* WeWork29x29@2x~ipad.png */; };
3F5689CE23262F2200FE42DE /* Lark40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895723262F1F00FE42DE /* Lark40x40@3x.png */; };
3F5689CF23262F2200FE42DE /* Tim40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895823262F1F00FE42DE /* Tim40x40@2x.png */; };
3F5689D023262F2200FE42DE /* Tim20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895923262F1F00FE42DE /* Tim20x20@2x~ipad.png */; };
3F5689D123262F2200FE42DE /* DingDing20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895A23262F1F00FE42DE /* DingDing20x20~ipad.png */; };
3F5689D223262F2200FE42DE /* Lark29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895B23262F1F00FE42DE /* Lark29x29@3x.png */; };
3F5689D323262F2200FE42DE /* WeChat40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895C23262F1F00FE42DE /* WeChat40x40@2x.png */; };
3F5689D423262F2200FE42DE /* Lark76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895D23262F1F00FE42DE /* Lark76x76~ipad.png */; };
3F5689D523262F2200FE42DE /* DingDing76x76@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895E23262F1F00FE42DE /* DingDing76x76@2x~ipad.png */; };
3F5689D623262F2200FE42DE /* NeiXin40x40~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56895F23262F1F00FE42DE /* NeiXin40x40~ipad.png */; };
3F5689D723262F2200FE42DE /* WeWork40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896023262F1F00FE42DE /* WeWork40x40@2x~ipad.png */; };
3F5689D823262F2200FE42DE /* Tim20x20@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896123262F2000FE42DE /* Tim20x20@2x.png */; };
3F5689D923262F2200FE42DE /* WeWork29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896223262F2000FE42DE /* WeWork29x29@3x.png */; };
3F5689DA23262F2200FE42DE /* WeChat60x60@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896323262F2000FE42DE /* WeChat60x60@2x.png */; };
3F5689DB23262F2200FE42DE /* Tim20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896423262F2000FE42DE /* Tim20x20~ipad.png */; };
3F5689DC23262F2200FE42DE /* WeChat83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896523262F2000FE42DE /* WeChat83.5x83.5@2x~ipad.png */; };
3F5689DD23262F2200FE42DE /* WeWork20x20@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896623262F2000FE42DE /* WeWork20x20@2x~ipad.png */; };
3F5689DE23262F2200FE42DE /* Tim60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896723262F2000FE42DE /* Tim60x60@3x.png */; };
3F5689DF23262F2200FE42DE /* WeChat20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896823262F2000FE42DE /* WeChat20x20@3x.png */; };
3F5689E023262F2200FE42DE /* QQ20x20~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896923262F2000FE42DE /* QQ20x20~ipad.png */; };
3F5689E123262F2200FE42DE /* QQ40x40@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896A23262F2000FE42DE /* QQ40x40@2x.png */; };
3F5689E223262F2200FE42DE /* QQ29x29@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896B23262F2000FE42DE /* QQ29x29@2x~ipad.png */; };
3F5689E323262F2200FE42DE /* QQ83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896C23262F2100FE42DE /* QQ83.5x83.5@2x~ipad.png */; };
3F5689E423262F2200FE42DE /* Lark20x20@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896D23262F2100FE42DE /* Lark20x20@3x.png */; };
3F5689E523262F2200FE42DE /* DingDing29x29@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896E23262F2100FE42DE /* DingDing29x29@3x.png */; };
3F5689E623262F2200FE42DE /* WeWork83.5x83.5@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56896F23262F2100FE42DE /* WeWork83.5x83.5@2x~ipad.png */; };
3F5689E723262F2200FE42DE /* QQ60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897023262F2100FE42DE /* QQ60x60@3x.png */; };
3F5689E823262F2200FE42DE /* DingDing40x40@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897123262F2100FE42DE /* DingDing40x40@3x.png */; };
3F5689E923262F2200FE42DE /* WeChat29x29@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897223262F2100FE42DE /* WeChat29x29@2x.png */; };
3F5689EA23262F2200FE42DE /* QQ76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897323262F2100FE42DE /* QQ76x76~ipad.png */; };
3F5689EB23262F2200FE42DE /* DingDing40x40@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897423262F2100FE42DE /* DingDing40x40@2x~ipad.png */; };
3F5689EC23262F2200FE42DE /* DingDing29x29~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897523262F2100FE42DE /* DingDing29x29~ipad.png */; };
3F5689ED23262F2200FE42DE /* WeWork76x76~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 3F56897623262F2100FE42DE /* WeWork76x76~ipad.png */; };
3F63118F23222EFE0004E0A1 /* TLocationPluginLocationConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F63118D23222EFE0004E0A1 /* TLocationPluginLocationConverter.h */; };
3F63119023222EFE0004E0A1 /* TLocationPluginLocationConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F63118E23222EFE0004E0A1 /* TLocationPluginLocationConverter.m */; };
3F94F9F7231F7F7800EA742C /* TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F94F9F5231F7F7800EA742C /* TLocationPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
3F94F9FF231F813100EA742C /* NSObject+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F94F9FD231F813100EA742C /* NSObject+TLocationPlugin.h */; };
3F94FA00231F813100EA742C /* NSObject+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F94F9FE231F813100EA742C /* NSObject+TLocationPlugin.m */; };
3F9CDAA52321F020000E7A24 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F9CDAA42321F020000E7A24 /* QuartzCore.framework */; };
3FA4496623242554005C5CAA /* UITableView+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FA4496423242554005C5CAA /* UITableView+TLocationPlugin.h */; };
3FA4496723242554005C5CAA /* UITableView+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FA4496523242554005C5CAA /* UITableView+TLocationPlugin.m */; };
3FB305F62320044900FD85A4 /* TSelectLocationDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FB305F32320044900FD85A4 /* TSelectLocationDataViewController.h */; };
3FB305F72320044900FD85A4 /* TSelectLocationDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FB305F42320044900FD85A4 /* TSelectLocationDataViewController.m */; };
3FB305F82320044900FD85A4 /* TSelectLocationDataViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3FB305F52320044900FD85A4 /* TSelectLocationDataViewController.xib */; };
3FB305FC2320063F00FD85A4 /* TAddLocationDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FB305F92320063F00FD85A4 /* TAddLocationDataViewController.h */; };
3FB305FD2320063F00FD85A4 /* TAddLocationDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FB305FA2320063F00FD85A4 /* TAddLocationDataViewController.m */; };
3FB305FE2320063F00FD85A4 /* TAddLocationDataViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3FB305FB2320063F00FD85A4 /* TAddLocationDataViewController.xib */; };
3FB30600232008E100FD85A4 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FB305FF232008E100FD85A4 /* MapKit.framework */; };
3FB306032320144700FD85A4 /* TLocationModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FB306012320144700FD85A4 /* TLocationModel.h */; };
3FB306042320144700FD85A4 /* TLocationModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FB306022320144700FD85A4 /* TLocationModel.m */; };
3FE3DFB8231FA8A5002711B6 /* TSafeRuntimeCFunc.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FE3DFB7231FA8A5002711B6 /* TSafeRuntimeCFunc.m */; };
3FEDEEC5231FAD10002E9C18 /* TLocationSettingViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEEC2231FAD10002E9C18 /* TLocationSettingViewController.h */; };
3FEDEEC6231FAD10002E9C18 /* TLocationSettingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEC3231FAD10002E9C18 /* TLocationSettingViewController.m */; };
3FEDEEC7231FAD10002E9C18 /* TLocationSettingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3FEDEEC4231FAD10002E9C18 /* TLocationSettingViewController.xib */; };
3FEDEEC8231FAF5B002E9C18 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FEDEEC0231FAA46002E9C18 /* CoreLocation.framework */; };
3FEDEED0231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEECE231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.h */; };
3FEDEED1231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEECF231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.m */; };
3FEDEED3231FDCF3002E9C18 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3FEDEED2231FDCF3002E9C18 /* AudioToolbox.framework */; };
3FEDEED62320AE6D002E9C18 /* TLocationTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEED42320AE6C002E9C18 /* TLocationTableViewCell.h */; };
3FEDEED72320AE6D002E9C18 /* TLocationTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEED52320AE6C002E9C18 /* TLocationTableViewCell.m */; };
3FEDEED92320B11C002E9C18 /* TLocationPluginImages.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 3FEDEED82320B11C002E9C18 /* TLocationPluginImages.bundle */; };
3FEDEEDC2320B14B002E9C18 /* UIImage+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEEDA2320B14B002E9C18 /* UIImage+TLocationPlugin.h */; };
3FEDEEDD2320B14B002E9C18 /* UIImage+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEDB2320B14B002E9C18 /* UIImage+TLocationPlugin.m */; };
3FEDEEE02320B1AF002E9C18 /* NSBundle+TLocationPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEEDE2320B1AF002E9C18 /* NSBundle+TLocationPlugin.h */; };
3FEDEEE12320B1AF002E9C18 /* NSBundle+TLocationPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEDF2320B1AF002E9C18 /* NSBundle+TLocationPlugin.m */; };
3FEDEEE72320B51F002E9C18 /* TLocationNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEEE52320B51F002E9C18 /* TLocationNavigationController.h */; };
3FEDEEE82320B51F002E9C18 /* TLocationNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEE62320B51F002E9C18 /* TLocationNavigationController.m */; };
3FEDEEEB2320C82E002E9C18 /* TBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FEDEEE92320C82D002E9C18 /* TBaseViewController.h */; };
3FEDEEEC2320C82E002E9C18 /* TBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEEA2320C82E002E9C18 /* TBaseViewController.m */; };
3FEDEEF52320C916002E9C18 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEF42320C916002E9C18 /* AppDelegate.m */; };
3FEDEEF82320C916002E9C18 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEEF72320C916002E9C18 /* ViewController.m */; };
3FEDEEFB2320C916002E9C18 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3FEDEEF92320C916002E9C18 /* Main.storyboard */; };
3FEDEEFD2320C91A002E9C18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3FEDEEFC2320C91A002E9C18 /* Assets.xcassets */; };
3FEDEF002320C91A002E9C18 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3FEDEEFE2320C91A002E9C18 /* LaunchScreen.storyboard */; };
3FEDEF032320C91A002E9C18 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FEDEF022320C91A002E9C18 /* main.m */; };
3FEDEF092320C93B002E9C18 /* TLocationPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F94F9F2231F7F7800EA742C /* TLocationPlugin.framework */; };
3FEDEF0A2320C93B002E9C18 /* TLocationPlugin.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F94F9F2231F7F7800EA742C /* TLocationPlugin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
3FF4458923214E880073D346 /* UIWindow+TLocationPluginToast.h in Headers */ = {isa = PBXBuildFile; fileRef = 3FF4458723214E880073D346 /* UIWindow+TLocationPluginToast.h */; };
3FF4458A23214E880073D346 /* UIWindow+TLocationPluginToast.m in Sources */ = {isa = PBXBuildFile; fileRef = 3FF4458823214E880073D346 /* UIWindow+TLocationPluginToast.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
3F6B15062327D58700BA3E5E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 3F6B15022327D58700BA3E5E /* yololib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = AD49F4E51769B63A00B8D2E0;
remoteInfo = yololib;
};
3FEDEF072320C92C002E9C18 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 3F94F9E9231F7F7800EA742C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3F94F9F1231F7F7800EA742C;
remoteInfo = TLocationPlugin;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
3FEDEF0B2320C93B002E9C18 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3FEDEF0A2320C93B002E9C18 /* TLocationPlugin.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
3F0A640E23217506002FA767 /* CALayer+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CALayer+TLocationPlugin.h"; sourceTree = ""; };
3F0A640F23217506002FA767 /* CALayer+TLocationPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CALayer+TLocationPlugin.m"; sourceTree = ""; };
3F0FE50F2320FBFC008B0830 /* TLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TLocationManager.h; sourceTree = ""; };
3F0FE5102320FBFC008B0830 /* TLocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TLocationManager.m; sourceTree = ""; };
3F344C0A23227F2F000A0D9F /* TAlertController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TAlertController.h; sourceTree = ""; };
3F344C0B23227F2F000A0D9F /* TAlertController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TAlertController.m; sourceTree = ""; };
3F344C0E2322937F000A0D9F /* TLocationDefine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationDefine.h; sourceTree = ""; };
3F35B14A2325405F00E785B9 /* devices_arm_info.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = devices_arm_info.sh; sourceTree = ""; };
3F35B14B2325431200E785B9 /* UIApplication+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIApplication+TLocationPlugin.h"; sourceTree = ""; };
3F35B14C2325431200E785B9 /* UIApplication+TLocationPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIApplication+TLocationPlugin.m"; sourceTree = ""; };
3F35B14F2325436B00E785B9 /* UIViewController+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+TLocationPlugin.h"; sourceTree = ""; };
3F35B1502325436B00E785B9 /* UIViewController+TLocationPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+TLocationPlugin.m"; sourceTree = ""; };
3F542A922325F15600497668 /* env.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = env.sh; sourceTree = ""; };
3F542A9323261BE200497668 /* inject_app_icon.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = inject_app_icon.py; sourceTree = ""; };
3F542A9423261EAB00497668 /* logos */ = {isa = PBXFileReference; lastKnownFileType = folder; path = logos; sourceTree = ""; };
3F542A952326225500497668 /* TLocationChangeAppICONViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationChangeAppICONViewController.h; sourceTree = ""; };
3F542A962326225500497668 /* TLocationChangeAppICONViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLocationChangeAppICONViewController.m; sourceTree = ""; };
3F542A972326225500497668 /* TLocationChangeAppICONViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TLocationChangeAppICONViewController.xib; sourceTree = ""; };
3F56890023262F1B00FE42DE /* QQ29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ29x29@2x.png"; sourceTree = ""; };
3F56890123262F1B00FE42DE /* Tim29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim29x29@2x~ipad.png"; sourceTree = ""; };
3F56890223262F1B00FE42DE /* WeChat29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat29x29@2x~ipad.png"; sourceTree = ""; };
3F56890323262F1B00FE42DE /* Lark60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark60x60@3x.png"; sourceTree = ""; };
3F56890423262F1B00FE42DE /* NeiXin60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin60x60@3x.png"; sourceTree = ""; };
3F56890523262F1B00FE42DE /* WeChat76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat76x76@2x~ipad.png"; sourceTree = ""; };
3F56890623262F1B00FE42DE /* WeWork20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork20x20~ipad.png"; sourceTree = ""; };
3F56890723262F1B00FE42DE /* Tim76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim76x76@2x~ipad.png"; sourceTree = ""; };
3F56890823262F1B00FE42DE /* DingDing60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing60x60@2x.png"; sourceTree = ""; };
3F56890923262F1B00FE42DE /* WeWork40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork40x40@3x.png"; sourceTree = ""; };
3F56890A23262F1B00FE42DE /* DingDing20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing20x20@2x~ipad.png"; sourceTree = ""; };
3F56890B23262F1B00FE42DE /* NeiXin20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin20x20~ipad.png"; sourceTree = ""; };
3F56890C23262F1C00FE42DE /* NeiXin20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin20x20@2x.png"; sourceTree = ""; };
3F56890D23262F1C00FE42DE /* Lark83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56890E23262F1C00FE42DE /* DingDing20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing20x20@3x.png"; sourceTree = ""; };
3F56890F23262F1C00FE42DE /* NeiXin76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin76x76@2x~ipad.png"; sourceTree = ""; };
3F56891023262F1C00FE42DE /* Lark76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark76x76@2x~ipad.png"; sourceTree = ""; };
3F56891123262F1C00FE42DE /* QQ20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ20x20@3x.png"; sourceTree = ""; };
3F56891223262F1C00FE42DE /* WeWork29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork29x29~ipad.png"; sourceTree = ""; };
3F56891323262F1C00FE42DE /* QQ40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ40x40@3x.png"; sourceTree = ""; };
3F56891423262F1C00FE42DE /* NeiXin29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin29x29@3x.png"; sourceTree = ""; };
3F56891523262F1C00FE42DE /* WeChat20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat20x20~ipad.png"; sourceTree = ""; };
3F56891623262F1C00FE42DE /* NeiXin40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin40x40@2x.png"; sourceTree = ""; };
3F56891723262F1C00FE42DE /* WeWork40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork40x40~ipad.png"; sourceTree = ""; };
3F56891823262F1C00FE42DE /* WeWork20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork20x20@2x.png"; sourceTree = ""; };
3F56891923262F1C00FE42DE /* Lark40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark40x40@2x~ipad.png"; sourceTree = ""; };
3F56891A23262F1C00FE42DE /* QQ20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ20x20@2x.png"; sourceTree = ""; };
3F56891B23262F1C00FE42DE /* WeChat29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat29x29~ipad.png"; sourceTree = ""; };
3F56891C23262F1C00FE42DE /* WeChat20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat20x20@2x~ipad.png"; sourceTree = ""; };
3F56891D23262F1C00FE42DE /* WeChat40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat40x40~ipad.png"; sourceTree = ""; };
3F56891E23262F1C00FE42DE /* Tim40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim40x40~ipad.png"; sourceTree = ""; };
3F56891F23262F1C00FE42DE /* WeWork60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork60x60@2x.png"; sourceTree = ""; };
3F56892023262F1C00FE42DE /* Lark60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark60x60@2x.png"; sourceTree = ""; };
3F56892123262F1C00FE42DE /* Lark29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark29x29@2x.png"; sourceTree = ""; };
3F56892223262F1C00FE42DE /* QQ40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ40x40@2x~ipad.png"; sourceTree = ""; };
3F56892323262F1D00FE42DE /* NeiXin29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin29x29@2x~ipad.png"; sourceTree = ""; };
3F56892423262F1D00FE42DE /* DingDing40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing40x40@2x.png"; sourceTree = ""; };
3F56892523262F1D00FE42DE /* WeChat20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat20x20@2x.png"; sourceTree = ""; };
3F56892623262F1D00FE42DE /* Lark20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark20x20@2x.png"; sourceTree = ""; };
3F56892723262F1D00FE42DE /* QQ20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ20x20@2x~ipad.png"; sourceTree = ""; };
3F56892823262F1D00FE42DE /* NeiXin40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin40x40@3x.png"; sourceTree = ""; };
3F56892923262F1D00FE42DE /* Lark29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark29x29~ipad.png"; sourceTree = ""; };
3F56892A23262F1D00FE42DE /* WeChat60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat60x60@3x.png"; sourceTree = ""; };
3F56892B23262F1D00FE42DE /* WeWork40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork40x40@2x.png"; sourceTree = ""; };
3F56892C23262F1D00FE42DE /* WeChat76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat76x76~ipad.png"; sourceTree = ""; };
3F56892D23262F1D00FE42DE /* WeWork20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork20x20@3x.png"; sourceTree = ""; };
3F56892E23262F1D00FE42DE /* Tim76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim76x76~ipad.png"; sourceTree = ""; };
3F56892F23262F1D00FE42DE /* QQ40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ40x40~ipad.png"; sourceTree = ""; };
3F56893023262F1D00FE42DE /* Tim29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim29x29@3x.png"; sourceTree = ""; };
3F56893123262F1D00FE42DE /* NeiXin60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin60x60@2x.png"; sourceTree = ""; };
3F56893223262F1D00FE42DE /* DingDing76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing76x76~ipad.png"; sourceTree = ""; };
3F56893323262F1D00FE42DE /* DingDing20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing20x20@2x.png"; sourceTree = ""; };
3F56893423262F1D00FE42DE /* WeWork60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork60x60@3x.png"; sourceTree = ""; };
3F56893523262F1D00FE42DE /* QQ60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ60x60@2x.png"; sourceTree = ""; };
3F56893623262F1D00FE42DE /* Lark40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark40x40@2x.png"; sourceTree = ""; };
3F56893723262F1D00FE42DE /* Lark29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark29x29@2x~ipad.png"; sourceTree = ""; };
3F56893823262F1D00FE42DE /* WeChat29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat29x29@3x.png"; sourceTree = ""; };
3F56893923262F1E00FE42DE /* NeiXin40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin40x40@2x~ipad.png"; sourceTree = ""; };
3F56893A23262F1E00FE42DE /* Tim20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim20x20@3x.png"; sourceTree = ""; };
3F56893B23262F1E00FE42DE /* QQ29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ29x29@3x.png"; sourceTree = ""; };
3F56893C23262F1E00FE42DE /* Tim40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim40x40@3x.png"; sourceTree = ""; };
3F56893D23262F1E00FE42DE /* Tim60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim60x60@2x.png"; sourceTree = ""; };
3F56893E23262F1E00FE42DE /* DingDing29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing29x29@2x.png"; sourceTree = ""; };
3F56893F23262F1E00FE42DE /* Tim29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim29x29~ipad.png"; sourceTree = ""; };
3F56894023262F1E00FE42DE /* Lark20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark20x20~ipad.png"; sourceTree = ""; };
3F56894123262F1E00FE42DE /* QQ76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ76x76@2x~ipad.png"; sourceTree = ""; };
3F56894223262F1E00FE42DE /* WeChat40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat40x40@2x~ipad.png"; sourceTree = ""; };
3F56894323262F1E00FE42DE /* Tim29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim29x29@2x.png"; sourceTree = ""; };
3F56894423262F1E00FE42DE /* DingDing60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing60x60@3x.png"; sourceTree = ""; };
3F56894523262F1E00FE42DE /* WeChat40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat40x40@3x.png"; sourceTree = ""; };
3F56894623262F1E00FE42DE /* WeWork29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork29x29@2x.png"; sourceTree = ""; };
3F56894723262F1E00FE42DE /* Tim83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56894823262F1E00FE42DE /* NeiXin83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56894923262F1E00FE42DE /* DingDing40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing40x40~ipad.png"; sourceTree = ""; };
3F56894A23262F1E00FE42DE /* Tim40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim40x40@2x~ipad.png"; sourceTree = ""; };
3F56894B23262F1E00FE42DE /* DingDing83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56894C23262F1E00FE42DE /* QQ29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ29x29~ipad.png"; sourceTree = ""; };
3F56894D23262F1E00FE42DE /* Lark40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark40x40~ipad.png"; sourceTree = ""; };
3F56894E23262F1E00FE42DE /* NeiXin20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin20x20@3x.png"; sourceTree = ""; };
3F56894F23262F1E00FE42DE /* NeiXin20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin20x20@2x~ipad.png"; sourceTree = ""; };
3F56895023262F1E00FE42DE /* NeiXin76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin76x76~ipad.png"; sourceTree = ""; };
3F56895123262F1F00FE42DE /* WeWork76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork76x76@2x~ipad.png"; sourceTree = ""; };
3F56895223262F1F00FE42DE /* Lark20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark20x20@2x~ipad.png"; sourceTree = ""; };
3F56895323262F1F00FE42DE /* NeiXin29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin29x29@2x.png"; sourceTree = ""; };
3F56895423262F1F00FE42DE /* DingDing29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing29x29@2x~ipad.png"; sourceTree = ""; };
3F56895523262F1F00FE42DE /* NeiXin29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin29x29~ipad.png"; sourceTree = ""; };
3F56895623262F1F00FE42DE /* WeWork29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork29x29@2x~ipad.png"; sourceTree = ""; };
3F56895723262F1F00FE42DE /* Lark40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark40x40@3x.png"; sourceTree = ""; };
3F56895823262F1F00FE42DE /* Tim40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim40x40@2x.png"; sourceTree = ""; };
3F56895923262F1F00FE42DE /* Tim20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim20x20@2x~ipad.png"; sourceTree = ""; };
3F56895A23262F1F00FE42DE /* DingDing20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing20x20~ipad.png"; sourceTree = ""; };
3F56895B23262F1F00FE42DE /* Lark29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark29x29@3x.png"; sourceTree = ""; };
3F56895C23262F1F00FE42DE /* WeChat40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat40x40@2x.png"; sourceTree = ""; };
3F56895D23262F1F00FE42DE /* Lark76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark76x76~ipad.png"; sourceTree = ""; };
3F56895E23262F1F00FE42DE /* DingDing76x76@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing76x76@2x~ipad.png"; sourceTree = ""; };
3F56895F23262F1F00FE42DE /* NeiXin40x40~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NeiXin40x40~ipad.png"; sourceTree = ""; };
3F56896023262F1F00FE42DE /* WeWork40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork40x40@2x~ipad.png"; sourceTree = ""; };
3F56896123262F2000FE42DE /* Tim20x20@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim20x20@2x.png"; sourceTree = ""; };
3F56896223262F2000FE42DE /* WeWork29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork29x29@3x.png"; sourceTree = ""; };
3F56896323262F2000FE42DE /* WeChat60x60@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat60x60@2x.png"; sourceTree = ""; };
3F56896423262F2000FE42DE /* Tim20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim20x20~ipad.png"; sourceTree = ""; };
3F56896523262F2000FE42DE /* WeChat83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56896623262F2000FE42DE /* WeWork20x20@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork20x20@2x~ipad.png"; sourceTree = ""; };
3F56896723262F2000FE42DE /* Tim60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Tim60x60@3x.png"; sourceTree = ""; };
3F56896823262F2000FE42DE /* WeChat20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat20x20@3x.png"; sourceTree = ""; };
3F56896923262F2000FE42DE /* QQ20x20~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ20x20~ipad.png"; sourceTree = ""; };
3F56896A23262F2000FE42DE /* QQ40x40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ40x40@2x.png"; sourceTree = ""; };
3F56896B23262F2000FE42DE /* QQ29x29@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ29x29@2x~ipad.png"; sourceTree = ""; };
3F56896C23262F2100FE42DE /* QQ83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56896D23262F2100FE42DE /* Lark20x20@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Lark20x20@3x.png"; sourceTree = ""; };
3F56896E23262F2100FE42DE /* DingDing29x29@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing29x29@3x.png"; sourceTree = ""; };
3F56896F23262F2100FE42DE /* WeWork83.5x83.5@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork83.5x83.5@2x~ipad.png"; sourceTree = ""; };
3F56897023262F2100FE42DE /* QQ60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ60x60@3x.png"; sourceTree = ""; };
3F56897123262F2100FE42DE /* DingDing40x40@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing40x40@3x.png"; sourceTree = ""; };
3F56897223262F2100FE42DE /* WeChat29x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeChat29x29@2x.png"; sourceTree = ""; };
3F56897323262F2100FE42DE /* QQ76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "QQ76x76~ipad.png"; sourceTree = ""; };
3F56897423262F2100FE42DE /* DingDing40x40@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing40x40@2x~ipad.png"; sourceTree = ""; };
3F56897523262F2100FE42DE /* DingDing29x29~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "DingDing29x29~ipad.png"; sourceTree = ""; };
3F56897623262F2100FE42DE /* WeWork76x76~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WeWork76x76~ipad.png"; sourceTree = ""; };
3F63118D23222EFE0004E0A1 /* TLocationPluginLocationConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationPluginLocationConverter.h; sourceTree = ""; };
3F63118E23222EFE0004E0A1 /* TLocationPluginLocationConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLocationPluginLocationConverter.m; sourceTree = ""; };
3F6B15022327D58700BA3E5E /* yololib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = yololib.xcodeproj; path = yololib/yololib.xcodeproj; sourceTree = ""; };
3F94F9F2231F7F7800EA742C /* TLocationPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TLocationPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3F94F9F5231F7F7800EA742C /* TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationPlugin.h; sourceTree = ""; };
3F94F9F6231F7F7800EA742C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
3F94F9FD231F813100EA742C /* NSObject+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+TLocationPlugin.h"; sourceTree = ""; };
3F94F9FE231F813100EA742C /* NSObject+TLocationPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+TLocationPlugin.m"; sourceTree = ""; };
3F9CDAA22321F013000E7A24 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
3F9CDAA42321F020000E7A24 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
3F9CDAAC2321F2A7000E7A24 /* build_all.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = build_all.sh; sourceTree = ""; };
3FA4496423242554005C5CAA /* UITableView+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UITableView+TLocationPlugin.h"; sourceTree = ""; };
3FA4496523242554005C5CAA /* UITableView+TLocationPlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UITableView+TLocationPlugin.m"; sourceTree = ""; };
3FB305F32320044900FD85A4 /* TSelectLocationDataViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TSelectLocationDataViewController.h; sourceTree = ""; };
3FB305F42320044900FD85A4 /* TSelectLocationDataViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSelectLocationDataViewController.m; sourceTree = ""; };
3FB305F52320044900FD85A4 /* TSelectLocationDataViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TSelectLocationDataViewController.xib; sourceTree = ""; };
3FB305F92320063F00FD85A4 /* TAddLocationDataViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TAddLocationDataViewController.h; sourceTree = ""; };
3FB305FA2320063F00FD85A4 /* TAddLocationDataViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TAddLocationDataViewController.m; sourceTree = ""; };
3FB305FB2320063F00FD85A4 /* TAddLocationDataViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TAddLocationDataViewController.xib; sourceTree = ""; };
3FB305FF232008E100FD85A4 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/MapKit.framework; sourceTree = DEVELOPER_DIR; };
3FB306012320144700FD85A4 /* TLocationModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationModel.h; sourceTree = ""; };
3FB306022320144700FD85A4 /* TLocationModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLocationModel.m; sourceTree = ""; };
3FC34C7E2322536600C15E66 /* inject.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = inject.sh; sourceTree = ""; };
3FE3DFB6231FA8A3002711B6 /* TSafeRuntimeCFunc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TSafeRuntimeCFunc.h; sourceTree = ""; };
3FE3DFB7231FA8A5002711B6 /* TSafeRuntimeCFunc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSafeRuntimeCFunc.m; sourceTree = ""; };
3FEDEEC0231FAA46002E9C18 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
3FEDEEC2231FAD10002E9C18 /* TLocationSettingViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationSettingViewController.h; sourceTree = ""; };
3FEDEEC3231FAD10002E9C18 /* TLocationSettingViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLocationSettingViewController.m; sourceTree = ""; };
3FEDEEC4231FAD10002E9C18 /* TLocationSettingViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TLocationSettingViewController.xib; sourceTree = ""; };
3FEDEECE231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIWindow+TLocationPluginTouch.h"; sourceTree = ""; };
3FEDEECF231FDB49002E9C18 /* UIWindow+TLocationPluginTouch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+TLocationPluginTouch.m"; sourceTree = ""; };
3FEDEED2231FDCF3002E9C18 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
3FEDEED42320AE6C002E9C18 /* TLocationTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLocationTableViewCell.h; sourceTree = ""; };
3FEDEED52320AE6C002E9C18 /* TLocationTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLocationTableViewCell.m; sourceTree = ""; };
3FEDEED82320B11C002E9C18 /* TLocationPluginImages.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TLocationPluginImages.bundle; sourceTree = ""; };
3FEDEEDA2320B14B002E9C18 /* UIImage+TLocationPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+TLocationPlugin.h"; sourceTree = "