第三方网络库AFNetworking

必备知识架构-第三方网络库AFNetworking

[toc]

知识架构

iOS知识库

Android知识库

AFNetworking源码解析与面试考点思考

AFNetworking源码解析与面试考点思考

八、多线程–第三方库AFNetworking

< 返回目录

1、AFNetworking源码解析

2、AFNetworking的线程和信号量问题

AFNetworking3.0后为什么不再需要常驻线程?

AFNetworking3.0后为什么不再需要常驻线程?

B.一个请求一条线程

如果来一个请求开辟一条线程,设置runloop保活线程,等待结果回调。这种方式理论上是可行的,但是你也看到了,线程开销太大了。(PASS)

C.一条常驻线程

只开辟一条子线程,设置runloop使线程常驻。所有的请求在这个线程上发起、同时也在这个线程上处理回调

线程保活的代码

1
2
3
4
5
6
7
8
9
+ (void)aliveThread {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}

我们知道主线程一直是保活的;而新建的子线程默认是没有添加Runloop的,因此给这个线程添加了一个runloop,并且加了一个NSMachPort,来防止这个新建的线程由于没有活动直接退出。

AFNetworking一些API介绍

必知点:AFNetworking框架默认请求类型requestSerializer和响应类型responseSerializer都是JSON格式的,即默认请求类型为AFJSONRequestSerializer,默认相应类型为AFJSONResponseSerializer

1、关于请求类型及请求参数的书写

所以在进行请求时候,我们必须根据自己请求的参数类型parameters,对AFNetworking的请求类型进行设置。主要设置为:

  1. 如果请求参数是字典类型NSDictionary,则请求类型应设置AFHTTPRequestSerializer
  2. 如果请求参数是JSON类型,则请求类型应设置AFJSONRequestSerializer

因为设置的类型不同,AFNetworking会根据设置的类型执行该类型下面对应的- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request withParameters:(id)parameters error:(NSError *__autoreleasing *)error方法。

其中

AFHTTPRequestSerializer对参数会有如下第496行的处理query = AFQueryStringFromParameters(parameters);该处理为将字典类型转为一串请求的字符串格式。

AFJSONRequestSerializer对参数的处理主要为第1260行的
[mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];

2、关于响应类型及响应response

响应的时候,AFURLSessionManager其会调用AFURLSessionManagerTaskDelegate协议,执行该协议里第292的responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];可以看出这里会根据我们设置的不同响应类型,调用该响应类型下的

1
2
3
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error

所以,这里我们衍生出一个继承自AFJSONResponseSerializer的CJJSONResponseSerializer的新响应类型,重写该方法,用来处理服务端返回的JSON不是标准的json格式的问题,即主要处理AFNetworking 3840的错误。

END

< 返回目录

提示语优化

[toc]

提示语优化

一、提示语优化

如果有一个提示语在显示中,其他同类提示语不再显示

提示语消失后,如果异常仍然存在,按上述规则显示第一个错误提示语

如果两类提示语需要出现,后面的覆盖前面。任何时间,只显示一条提示语

End

iOS进阶_打包脚本

[TOC]

一、认识Mac的keychain机制

要使用Keychain中的证书,请先unlock-keychain

完整的命令如下:

1
security unlock-keychain -p "lichaoqian" "/Users/lichaoqian/Library/Keychains/login.keychain"

如果你是在Jenkins中执行的,请确保你的权限问题。具体的解决可进入《使用工具->Jenkins->Jenkins使用问题常见》中的”二、权限问题”中查看解决。

其他参考文章:

二、认识几个命令

  • 查看SDK版本
1
xcodebuild -showsdks

查询结果如下:

xcodebuild -showsdks的执行结果

三、认识执行命令

在终端执行xcodebuild --help

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
Beyond-MacBook-Pro:~ lichaoqian$ xcodebuild --help
Usage: xcodebuild [-project <projectname>] [[-target <targetname>]...|-alltargets] [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings [-json]] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild [-project <projectname>] -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings [-json]] [-showdestinations] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild -workspace <workspacename> -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [-showdestinations] [<buildsetting>=<value>]... [<buildaction>]...
xcodebuild -version [-sdk [<sdkfullpath>|<sdkname>] [-json] [<infoitem>] ]
xcodebuild -list [[-project <projectname>]|[-workspace <workspacename>]] [-json]
xcodebuild -showsdks [-json]
xcodebuild -exportArchive -archivePath <xcarchivepath> [-exportPath <destinationpath>] -exportOptionsPlist <plistpath>
xcodebuild -exportNotarizedApp -archivePath <xcarchivepath> -exportPath <destinationpath>
xcodebuild -exportLocalizations -localizationPath <path> -project <projectname> [-exportLanguage <targetlanguage>...[-includeScreenshots]]
xcodebuild -importLocalizations -localizationPath <path> -project <projectname>
xcodebuild -resolvePackageDependencies [-project <projectname>|-workspace <workspacename>] -clonedSourcePackagesDirPath <path>
xcodebuild -create-xcframework [-help] [-framework <path>] [-library <path> [-headers <path>]] -output <path>

Options:
-usage print brief usage
-help print complete usage
-verbose provide additional status output
-license show the Xcode and SDK license agreements
-checkFirstLaunchStatus Check if any First Launch tasks need to be performed
-runFirstLaunch install packages and agree to the license
-project NAME build the project NAME
-target NAME build the target NAME
-alltargets build all targets
-workspace NAME build the workspace NAME
-scheme NAME build the scheme NAME
-configuration NAME use the build configuration NAME for building each target
-xcconfig PATH apply the build settings defined in the file at PATH as overrides
-arch ARCH build each target for the architecture ARCH; this will override architectures defined in the project
-sdk SDK use SDK as the name or path of the base SDK when building the project
-toolchain NAME use the toolchain with identifier or name NAME
-destination DESTINATIONSPECIFIER use the destination described by DESTINATIONSPECIFIER (a comma-separated set of key=value pairs describing the destination to use)
-destination-timeout TIMEOUT wait for TIMEOUT seconds while searching for the destination device
-parallelizeTargets build independent targets in parallel
-jobs NUMBER specify the maximum number of concurrent build operations
-maximum-concurrent-test-device-destinations NUMBER the maximum number of device destinations to test on concurrently
-maximum-concurrent-test-simulator-destinations NUMBER the maximum number of simulator destinations to test on concurrently
-parallel-testing-enabled YES|NO overrides the per-target setting in the scheme
-parallel-testing-worker-count NUMBER the exact number of test runners that will be spawned during parallel testing
-maximum-parallel-testing-workers NUMBER the maximum number of test runners that will be spawned during parallel testing
-dry-run do everything except actually running the commands
-quiet do not print any output except for warnings and errors
-hideShellScriptEnvironment don't show shell script environment variables in build log
-showsdks display a compact list of the installed SDKs
-showdestinations display a list of destinations
-showTestPlans display a list of test plans
-showBuildSettings display a list of build settings and values
-list lists the targets and configurations in a project, or the schemes in a workspace
-find-executable NAME display the full path to executable NAME in the provided SDK and toolchain
-find-library NAME display the full path to library NAME in the provided SDK and toolchain
-version display the version of Xcode; with -sdk will display info about one or all installed SDKs
-enableAddressSanitizer YES|NO turn the address sanitizer on or off
-enableThreadSanitizer YES|NO turn the thread sanitizer on or off
-enableUndefinedBehaviorSanitizer YES|NO turn the undefined behavior sanitizer on or off
-resultBundlePath PATH specifies the directory where a result bundle describing what occurred will be placed
-resultStreamPath PATH specifies the file where a result stream will be written to (the file must already exist)
-resultBundleVersion 3 [default] specifies which result bundle version should be used
-clonedSourcePackagesDirPath PATH specifies the directory to which remote source packages are fetch or expected to be found
-derivedDataPath PATH specifies the directory where build products and other derived data will go
-archivePath PATH specifies the directory where any created archives will be placed, or the archive that should be exported
-exportArchive specifies that an archive should be exported
-exportNotarizedApp export an archive that has been notarized by Apple
-exportOptionsPlist PATH specifies a path to a plist file that configures archive exporting
-enableCodeCoverage YES|NO turn code coverage on or off when testing
-exportPath PATH specifies the destination for the product exported from an archive
-skipUnavailableActions specifies that scheme actions that cannot be performed should be skipped instead of causing a failure
-exportLocalizations exports completed and outstanding project localizations
-importLocalizations imports localizations for a project, assuming any necessary localized resources have been created in Xcode
-localizationPath specifies a path to XLIFF localization files
-exportLanguage specifies multiple optional ISO 639-1 languages included in a localization export
-xctestrun specifies a path to a test run specification
-testPlan specifies the name of the test plan associated with the scheme to use for testing
-only-testing constrains testing by specifying tests to include, and excluding other tests
-only-testing:TEST-IDENTIFIER constrains testing by specifying tests to include, and excluding other tests
-skip-testing constrains testing by specifying tests to exclude, but including other tests
-skip-testing:TEST-IDENTIFIER constrains testing by specifying tests to exclude, but including other tests
-only-test-configuration constrains testing by specifying test configurations to include, and excluding other test configurations
-skip-test-configuration constrains testing by specifying test configurations to exclude, but including other test configurations
-testLanguage constrains testing by specifying ISO 639-1 language in which to run the tests
-testRegion constrains testing by specifying ISO 3166-1 region in which to run the tests
-resolvePackageDependencies resolves any Swift package dependencies referenced by the project or workspace
-disableAutomaticPackageResolution prevents packages from automatically being resolved to versions other than those recorded in the `Package.resolved` file
-json output as JSON (note: -json implies -quiet)
-allowProvisioningUpdates Allow xcodebuild to communicate with the Apple Developer website. For automatically signed targets, xcodebuild will create and update profiles, app IDs, and certificates. For manually signed targets, xcodebuild will download missing or updated provisioning profiles. Requires a developer account to have been added in Xcode's Accounts preference pane.
-allowProvisioningDeviceRegistration Allow xcodebuild to register your destination device on the developer portal if necessary. This flag only takes effect if -allowProvisioningUpdates is also passed.
-showBuildTimingSummary display a report of the timings of all the commands invoked during the build
-create-xcframework create an xcframework from prebuilt libraries; -help for more information.

Available keys for -exportOptionsPlist:

compileBitcode : Bool

For non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES.

destination : String

Determines whether the app is exported locally or uploaded to Apple. Options are export or upload. The available options vary based on the selected distribution method. Defaults to export.

embedOnDemandResourcesAssetPacksInBundle : Bool

For non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified.

generateAppStoreInformation : Bool

For App Store exports, should Xcode generate App Store Information for uploading with iTMSTransporter? Defaults to NO.

iCloudContainerEnvironment : String

If the app is using CloudKit, this configures the "com.apple.developer.icloud-container-environment" entitlement. Available options vary depending on the type of provisioning profile used, but may include: Development and Production.

installerSigningCertificate : String

For manual signing only. Provide a certificate name, SHA-1 hash, or automatic selector to use for signing. Automatic selectors allow Xcode to pick the newest installed certificate of a particular type. The available automatic selectors are "Mac Installer Distribution" and "Developer ID Installer". Defaults to an automatic certificate selector matching the current distribution method.

manifest : Dictionary

For non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on-demand resources.

method : String

Describes how Xcode should export the archive. Available options: app-store, validation, ad-hoc, package, enterprise, development, developer-id, and mac-application. The list of options varies based on the type of archive. Defaults to development.

onDemandResourcesAssetPacksBaseURL : String

For non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn't YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL.

provisioningProfiles : Dictionary

For manual signing only. Specify the provisioning profile to use for each executable in your app. Keys in this dictionary are the bundle identifiers of executables; values are the provisioning profile name or UUID to use.

signingCertificate : String

For manual signing only. Provide a certificate name, SHA-1 hash, or automatic selector to use for signing. Automatic selectors allow Xcode to pick the newest installed certificate of a particular type. The available automatic selectors are "Mac App Distribution", "iOS Distribution", "iOS Developer", "Developer ID Application", "Apple Distribution", "Mac Developer", and "Apple Development". Defaults to an automatic certificate selector matching the current distribution method.

signingStyle : String

The signing style to use when re-signing the app for distribution. Options are manual or automatic. Apps that were automatically signed when archived can be signed manually or automatically during distribution, and default to automatic. Apps that were manually signed when archived must be manually signed during distribtion, so the value of signingStyle is ignored.

stripSwiftSymbols : Bool

Should symbols be stripped from Swift libraries in your IPA? Defaults to YES.

teamID : String

The Developer Portal team to use for this export. Defaults to the team used to build the archive.

thinning : String

For non-App Store exports, should Xcode thin the package for one or more device variants? Available options: <none> (Xcode produces a non-thinned universal app), <thin-for-all-variants> (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. "iPhone7,1"). Defaults to <none>.

uploadBitcode : Bool

For App Store exports, should the package include bitcode? Defaults to YES.

uploadSymbols : Bool

For App Store exports, should the package include symbols? Defaults to YES.

1、cd到代码目录

2、开始打包

  • 执行命令

写在终端进行测试的命令:

1
xcodebuild -workspace CJAutoPackageDemo.xcworkspace -scheme App1Enterprise -configuration Debug -sdk iphoneos12.2 ARCHS='arm64 armv7' IOS_DEVELOPMENT_TARGET=8.0 -derivedDataPath ../output/build/Debug-iphoneos archive -archivePath ../output/Debug-iphoneos/App1Enterprise.xcarchive

写在脚本中的命令:

1
2
3
4
5
echo ""
echo ""
echo ">>>>>>>>>>>>>>>>>>>>>>>>>> step5:begin compile project >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
xcodebuild -workspace ${PROJECT_DIR}/${APPPROJECT_NAME}.xcworkspace -scheme ${APPTARGET_NAME} -configuration ${BUILD_CONFIGURATION_NAME} -sdk ${SIMULATOR_OR_IOS_SDK}${SDK_VERSION} ARCHS='arm64 armv7' IOS_DEVELOPMENT_TARGET=${DEVELOPMENT_TARGET} -derivedDataPath ${BUILD_OUTPUT_PATH} archive -archivePath "${ARCHIVE_OUTPUT_PATH}/${APPTARGET_NAME}.xcarchive"
echo "<<<<<<<<<<<<<<<<<<<<<<<<<<< step5:end compile project <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"

参数介绍:

参数 含义
-workspace 工程文件名(用cocopods集成的项目,没有的话 整个改为-xcodeproj xxx.xcodeproj)
-scheme 通过scheme指定不同的target
-configuration 对应的环境配置,就是编译的时候执行的模式
(测试Debug、预生产PreRelease、生产Release)
-archivePath 导出的.xcarchive的路径
-sdk
-derivedDataPath
-archivePath 导出的.xcarchive的路径

3、导出ipa

  • 执行命令
1
2
3
4
5
6
7
8
9
10
11
echo ""
echo ""
echo ">>>>>>>>>>>>>>>>>>>>>>>>>> step6:begin archiving app to ipa >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
echo "PWD=$PWD"
cd ${ROOT_DIR}
echo "PWD=$PWD"
echo "archivePath ==>>> ${ARCHIVE_OUTPUT_PATH}/${APPTARGET_NAME}.xcarchive"
echo "exportPath ==>>> ${ARCHIVE_OUTPUT_PATH}/${APPTARGET_NAME}"
echo "exportOptionsPlist ==>>> ${ExportOptionsPlist_PATH}"
xcodebuild -exportArchive -archivePath "${ARCHIVE_OUTPUT_PATH}/${APPTARGET_NAME}.xcarchive" -exportPath "${ARCHIVE_OUTPUT_PATH}/${APPTARGET_NAME}" -exportOptionsPlist "${ExportOptionsPlist_PATH}" -allowProvisioningUpdates
echo "<<<<<<<<<<<<<<<<<<<<<<<<<<< step6:end archiving app to ipa <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
  • 参数解读:
参数 含义
-archivePath .xcarchive文件的路径
-exportPath 导出的ipa的路径
-exportOptionsPlist

三、完整脚本内容(含使用Jenkins打包)

  • 测试项目工程详见:gitee中的AutoPackage-iOS工程

  • 测试Jenkins工程详见:本地Jenkins中的CJAutoPackage工程

  • 最终Jenkins脚本如下图:

    iOS打包_Jenkins脚本

附:没有权限问题的Jenkins正确的启动方式如下(按下面方式打开,才不会出现权限问题):

1
2
$ sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
$ java -jar /Applications/Jenkins/jenkins.war --httpPort=8080

当你执行完这两行命令的时候,你可以在浏览器上输入http://localhost:8080来访问Jenkins了。(如果你只执行了第一行,没执行第二行,会出现无法访问)

更多Jenkins知识请查看:实用工具->Jenkins->Jenkins的安装与启动

四、注意点

1、多环境的打包

主要注意为xcodebuild -workspace中的-configuration参数即可。

2、多Target的打包注意

多Target的Podfile文件ruby脚本内容,大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
source 'https://github.com/CocoaPods/Specs.git'
source 'https://gitee.com/dvlproad/dvlproadSpecs'

platform :ios, '8.0'
#use_frameworks!
inhibit_all_warnings!

post_install do |installer|

puts 'Determining pod project minimal deployment target'

pods_project = installer.pods_project
deployment_target_key = 'IPHONEOS_DEPLOYMENT_TARGET'
deployment_targets = pods_project.build_configurations.map{ |config| config.build_settings[deployment_target_key] }
minimal_deployment_target = deployment_targets.min_by{ |version| Gem::Version.new(version) }

puts 'Minimal deployment target is ' + minimal_deployment_target
puts 'Setting each pod deployment target to ' + minimal_deployment_target

installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings[deployment_target_key] = minimal_deployment_target
end
end
end


# There are no targets called "App1Common" in any Xcode projects
abstract_target 'App1Common' do
# Has its own copy of App1Common + App1Enterprise
target 'App1Enterprise' do

end

# Has its own copy of App1Common + App1AppStore
target 'App1AppStore' do

end
end



target 'CJAutoPackageDemoTests' do

end

通过脚本自动化打包的时候的注意点如下:

  1. 主要注意为xcodebuild -workspace中的-scheme参数即可。

  2. 多Target后,记得在Linked Frameworks and Libraries中删除已经不存在的原本旧的libPods-xxx.a文件。否则,Jenkins脚本打包Build的时候会报错。

    • Jenkins脚本打包Build的时候报错的信息如下:

    Jenkins脚本打包Build的时候报错的信息

    • 多Target工程打包时候要删除的旧引用文件如下:

      多Target工程打包时候要删除的旧引用文件

iOS证书

[TOC]

iOS证书

二、推送证书

image-20230302172748572

2、问题

1、iOS证书不受信任解决办法

image-20230302173013788

重新下载AppleWWDRCA并安装。即下载最新的AppleWWDR

image-20230302173155682

进入后

image-20230302173236106

进入后

image-20230302173318271

这里我们下载个G4就够了

2、iOS 推送证书无法导出p12文件

请一定要切换到”我的证书目录下”

image-20230302173554802

第4节、Jenkins使用问题常见

[TOC]

Jenkins上显示二维码图片

一、在Jenkins上显示二维码图片

持续集成 从零开始在 Jenkins 上显示打包二维码

1. 安装Jenkins插件

  • 进入Jenkins工作台系统管理>插件管理>可选插件>过滤>build-name-setter,勾选对应插件直接安装

    showQR1

  • 返回工作台首页,选择一个Build工程>配置

  • 可以看到构建环境处多了一个Set Build Name的选项,即插件安装成功

    showQR2

2. 配置Set Build Name插件

查看Jekins的环境变量参数,我们可以看到

1
2
3
4
BUILD_NUMBER
The current build number, such as "153"
BUILD_DISPLAY_NAME
The display name of the current build, which is something like "#153" by default.
  • Set Build Name就是修改这个BUILD_DISPLAY_NAME,默认为#${BUILD_NUMBER}

  • Jenkins的默认安全设置,会把所有的输入都当成纯文本,为了使图片链接生效,需要更改一下系统管理>全局安全配置>标记格式器,将纯文本选项改为Safe HTML,保存设置

    showQR3

  • 点击Set Build Name的高级,会出现Build Description的设置,可以在这里写入一个图片的链接 <img src="http://ww1.sinaimg.cn/large/007x9vWyly1g2zgykchtmj30a7064dk4.jpg" height="200" width="200/>

  • Build完成之后即可在Build历史中看到对应的图片链接

    img

showQR4_update1

End

第4节、Jenkins使用问题常见

Jenkins

[TOC]

前言

天啊,没遇到问题之前,你永远不知道我下面要讲的这些点是多么多么的重要。你只要稍微不注意,就会导致你所有的正确操作都变成错误。

Jenkins管理员密码忘记的解决办法

首先明确,不管是初始密码,还是找回管理员密码都是从共享--Jenkins--Home中处理,目录结果如下:
jenkins_Home

admin密码更改忘记情况

1.删除Jenkins目录下config.xml文件中下面代码,并保存文件。

1
2
3
4
5
6
7
8
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
<securityRealm class="hudson.security.HudsonPrivateSecurityRealm">
<disableSignup>true</disableSignup>
<enableCaptcha>false</enableCaptcha>
</securityRealm>

2.重启Jenkins服务 http://localhost:8080/restart

附:重新加载配置信息 http://localhost:8080/reload

3.进入首页>“系统管理”>“Configure Global Security”;

4.勾选“启用安全”;

5.点选“Jenkins专有用户数据库”,并点击“保存”;

6.重新点击首页>“系统管理”,发现此时出现“管理用户”;

7.点击进入展示“用户列表”;

8.点击右侧进入修改密码页面,修改后即可重新登录。

参考:忘记Jenkins管理员密码的解决办法

一、文件路径问题

Jenkins脚本中,不能使用桌面路径:

本地cd目录注意:

1
2
3
4
5
# 错误cd
# cd /Users/lichaoqian/Desktop/TestScript # 不能使用桌面路径,执行构建时候Jenkins会提示 `cd: /Users/lichaoqian/Desktop/TestScript: Not a directory`

# 正确cd
cd /Users/lichaoqian/Project/Test/TestScript

二、权限问题

1、问题例子

将在终端中已验证通过的如下脚本,放到Jenkins上执行。

问题例子1:文件修改
1
2
cd /Users/lichaoqian/Project/Test/TestScript
chmod -R 777 ./0000.txt

执行后,Jenkins的log如下:

Jenkins权限问题log

很显然这是个权限问题。

问题例子2:钥匙串Keychain解锁

同理的当你执行钥匙串Keychain的时候也会有权限问题

1
security unlock-keychain -p "lichaoqian" "/Users/lichaoqian/Library/Keychains/login.keychain"

unlock-keychain_1_JenkinsScript

执行后,Jenkins的log如下:

unlock-keychain_1_JenkinsErrorLog.png

1
2
3
4
5
[TestScript] $ /bin/sh -xe /Users/Shared/Jenkins/tmp/jenkins2455609193418764900.sh
+ security unlock-keychain -p lichaoqian /Users/lichaoqian/Library/Keychains/login.keychain
security: SecKeychainUnlock /Users/lichaoqian/Library/Keychains/login.keychain: Write permissions error.
Build step '执行 shell' marked build as failure
Finished: FAILURE

很显然这也是个权限问题。

2、权限问题分析

参考文章:iOS开发-自动化打包Jenkins集成的文章开头就有讲到。

原因:Jenkins打开姿势不对!

如果你构建的工程,是在/Users/Shared/Jenkins工作目录下,那么就会有权限问题。

如果你构建的工程,是在/Users/[user name]/.jenkins工作目录下,才不会有权限问题。

  • 错误的:有权限问题的Jenkins workspace目录

有权限问题的Jenkins workspace目录

  • 正确的:无权限问题的Jenkins workspace目录

无权限问题的Jenkins workspace目录

  • 如何验证你当前项目点击构建后的工作目录是哪里呢?

    答:直接构建,然后去查看你的项目显示在哪里啊。

3、权限问题解决(正确的启动Jenkins姿势)

在使用正确的启动Jenkins之前,我们先来认识下下面的这个org.jenkins-ci.plist文件。它的位置 /Library/LaunchDaemons/org.jenkins-ci.plist 如下:

正确的启动Jenkins姿势

没有权限问题的Jenkins正确的启动方式如下(按下面方式打开,才不会出现权限问题):

1
2
$ sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist
$ java -jar /Applications/Jenkins/jenkins.war --httpPort=8080

当你执行完这两行命令的时候,你可以在浏览器上输入http://localhost:8080来访问Jenkins了。(如果你只执行了第一行,没执行第二行,会出现无法访问)

4、解决后的结果显示

  • 4.1、脚本内容

脚本内容

  • 4.2、脚本执行结果

脚本执行结果

至此,你的权限问题已完美解决。

休息一下

三、其他权限问题

  • Jenkins问题解决方案:

解决:进入mac 系统偏好设置 — 用户与群组 — 其他用户 — jenkins ,勾选允许用户管理这台电脑

unlock-keychain_Write permissions error

勾选选项。

unlock-keychain_3_JenkinsSolve

四、Jenkins权限问题其他解决方法(未实践)

  • 未实践方式1(都未实践):

Jenkins执行脚本提示没有权限的解决办法 未实践,因为已经通过上述正确的启动Jenkins来解决了。所以这里没去实践。不过看内容应该是可行的。后续有时间再补充。

  • 未实践方式2(看了应该无效):

提高Jenkins用户权限,详见《Terminal -> 终端命令使用.md》中的用户相关操作。应该无效

iOS进阶_多Target

[TOC]

利用多Target开发相似app

一、问题背景

开发一个与之前几乎一样的app。只是app名字等基本信息变更。

错误做法 正确做法
项目 再创建了新的项目 使用同一项目
原因 极容易出现后来新开发的功能两个app都要支持 保证可共用到以后新开发的功能

下面我们开始介绍如何利用多Target开发相似app。

二、操作步骤

1、生成新的Target(这里推荐采用Duplicate方式,而不是File->New->Target)

1.1、Duplicate方法略。
1.2、Duplicate后,需要修改的东西
必选需修改项 操作方法 得到
Info.plist ①复制一份。
②并重新为Target选择Info.plist
③跟新Info.plist中的名字、签名等
App1Info.plist、App2Info.plist
Scheme Manager Scheme -> 双击重命名 新的App2Scheme
证书&描述文件 更具新的BundleId,添加证书&描述文件 真机编译通过

特别注意:add Info.plist等文件的时候,一定要注意选择对应的Target。不多多勾选☑️,也不要少勾选。

1.3、其他APP定制项更改
可选修改项 操作方法 得到
icon 修改InfoPlist 新APP的Icon
名字 修改InfoPlist 新APP的名字

2、Target区分

需求背景:有些共用的文件在不同的Target下是有细微不同的,那么我们在具体实现的时候就需要作出区分。

2.1、Objective-C、C、C++的LLVM预处理宏的添加

Objective-C、C、C++的LLVM预处理宏在Preprocessor Macros处定义。如图创建工程时已经默认创建好了在Debug时定义DEBUG=1 宏标记。

2.2、Swift

因为Swift 中没有宏定义的概念,因此我们不能使用 #ifdef 的方法来检查某个符号是否经过宏定义。

在项目的 Build Settings 中,找到 Swift Compiler - Custom Flags,并在其中的 Other Swift Flags

为APP1加上 -D APPTARGET1 就可以了;为APP2加上 -D APPTARGET2 就可以了;

其他参考文章:https://blog.csdn.net/kaiyuanheshang/article/details/78862382

解决办法:这里解决的方法是针对不同的Target在Preprocessor Macros中定义宏,如添加TargetTYPE

  • 在Preprocessor Macros中添加TARGETTYPE

PreprocessorMacros添加后

Target代码区分需用到的知识:

含义 示例
#if 既关心宏是否定义,又关心宏的逻辑的真假
#ifdef
#ifndef
仅仅关心宏是否被定义,不关心宏的逻辑真假

代码区分如下:

1
2
3
4
5
#if TARGETTYPE == 0
[AMapServices sharedServices].apiKey = @"6d79992bc988b60f68e059edeef82538";
#elif TARGETTYPE == 1
[AMapServices sharedServices].apiKey = @"aef6d9dabe4cdd1da9e923e52b5d40ca";
#endif

至此,你直接编译,发现”好像”完成了。实际上如果你的项目没有使用POD的,确实是到此就完成了 。

分割图1

下面我们额外补充,当你的项目有使用POD的时候,你还需要处理的东西。

3、Pod修改

在上述中,你可能发现好像我使用了POD的但是依然正确编译通过啊。

是的,是通过了,但是这是假象。或者准确的说,当你下次使用POD相关命令,如pod install的时候,你会发现之前的项目编译不通过了。

所以,你需要修改PodFile,并重新pod install。PodFile的修改方法如下:

1
2
3
4
5
6
7
8
9
target 'APP1' do
pod 'AFNetworking'
pod 'APP1SDK'
end

target 'APP2' do
pod 'AFNetworking'
pod 'APP2SDK'
end
  • 修改方式1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# There are no targets called "APPCommon" in any Xcode projects
abstract_target 'APPCommon' do
pod 'AFNetworking'

# Has its own copy of APPCommon + APP2SDK
target 'APP1' do
pod 'APP1SDK'
end

# Has its own copy of APPCommon + APP2SDK
target 'APP2' do
pod 'APP2SDK'
end
end
  • 修改方式2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 共用的第三方库
def AppCommon_Pods
pod 'AFNetworking'
end

# APP1所需的第三方库
target 'APP1' do
AppCommon_Pods
pod 'APP1SDK'
end

# APP2所需的第三方库
target 'APP2' do
AppCommon_Pods
pod 'APP2SDK'
end

最后修改完后,重新pod install后即可。

分割图1

4、脚本打包时候,因为多Target后旧的libPods-xxx(Framework)忘删除引起的问题

多Target后旧的libPods-xxx引起的问题

多Target后旧的libPods-xxx引起的问题

多Target后旧的libPods-xxx的问题解决否的判断

多Target后旧的libPods-xxx的问题解决否的判断

三、Swift中的条件编译

在C 系语言中,我们可以通过预处理宏定义一些参数,使用#if或者#ifdef编译条件分支来控制哪些代码需要编译,而哪些代码不需要。但是在swift中没有宏定义的概念,虽然不能使用 #ifdef 的方法来检查某个符号是否经过宏定义,但是可以支持“#if/#else/#endif”语句。

四、其他

只用一个target,配合一个脚本,可以进行茫茫多target的管理了

iOS进阶_多Configuration

[TOC]

利用多Configuration打包不同环境

前言

序言:

现象:Xcode默认只有DEBUG和RELEASE两种模式。

问题:如果我们在项目中想增加预发布环境或者再增加其他多个环境呢?

错误(不当)做法:如果在项目中用if else 弄个全局变量来控制,每次打包之前去手动修改,这样不仅繁琐,而且还会出错。

正确(推荐)做法:下面来一下在Xcode中添加多个环境变量的方法.

详细做法参考:使用Xcode增加环境变量(多种环境区分),不再累诉。

一、认识

1、几个描述文件的认识与区别

通过以下表格,你将认识到为什么你这个环境需要使用这个描述文件打包,用其他描述文件会有什么问题。

描述文件类型 可安装的设备 证书环境(开发/生产) 使用的推送 描述文件使用的环境(测试/预生产/生产)
development 已注册的设备 开发环境的证书 测试环境的推送 测试环境
adhoc 已注册的设备
(查看描述文件即可知道它没法做到在所有设备上都能安装的)
生产环境的证书 生产环境的推送
(这个创建描述文件的时候你就该知道的)
预生产环境
appstore/
inhouse
所有的设备 生产环境的证书 生产环境的推送 生产环境

2、几种环境的认识

环境 需要可以安装的设备 需要测试的推送
测试环境 在《已注册的设备》上可安装即可 测试环境的推送
预生产环境 至少《已注册的设备》上都能够安装吧 生产环境的推送
生产环境 要《所有的设备》上都能安装才行 生产环境的推送

3、环境与描述文件的总结

环境 应该使用的描述文件 备注
测试环境 development 不需要上线
预生产环境 adhoc 不需要上线
生产环境 appstore / inhouse 需要上线

4、Configuration的认识

4.1、错误认识

只知道Archive打包的时候使用的是Release模式,殊不知任何操作Archive打包的时候使用的模式都是可以通过Edit Scheme来更改的。

image-20190427145459385

4.2、正确认识:

他代表着各种配置。

二、问题背景

1、需要多Configuration的问题背景

对话:帮我打个测试包

对话:帮我打个预生产的包吧

对话:预生产测好了,帮我最后打个生产环境的包,我再测下,没问题就可以上线了。

那么,你就可能出现,每次打包的时候,去一个配置里面频繁修改证书(dev、adhoc、appstore/inhouse)。

为了避免每次打不同包,还得去那个Configuration里切换证书,你何不多建个Configuration呢?(Xcode默认的已经有且只有DEBUG和RELEASE两种模式)

2、多Configuration使用的问题背景

2.1、默认情况下的Configuration常见使用

Xcode默认只有DEBUG和RELEASE两种模式,如下图:

Xcode默认只有DEBUG和RELEASE两种模式

通常我们的做法:

Configuration 通过作为什么环境使用
DEBUG 开发环境
RELEASE 生产环境

2.2、默认情况下的Configuration使用的问题

问题:如果我们在项目中想增加预发布环境或者再增加其他多个环境呢?

错误(不当)做法 正确(推荐)做法
项目 从一开始就没考虑到Configuration的使用,在项目中用if else 弄个全局变量来控制,每次打包之前去手动修改 根据需要新增的环境个数,增加对应的Configuration个数。
原因 这样不仅繁琐,而且还会出错 确保不用修改代码,只需要在Edit Scheme中修改想要使用的Configuration即可。

三、操作步骤

1、生成新的Configuration(只能使用Duplicate方式)

1.1、Duplicate方法略。
1.2、Duplicate后,必须需要修改的东西
必选需修改项 操作方法 得到
更新新增Configuration使用的Pod 重新执行pod install

2、Configuration区分

需求背景:区分配置

解决办法:为Target的Prerelease Configuration在Preprocessor Macros中添加宏,如添加PRERELEASE=1

  • 在Preprocessor Macros中为我们刚新增的Prerelease的Configuration中添加PRERELEASE=1

多Configuration_PreprocessorMacros添加后

Configuration代码区分需用到的知识:

含义 示例
#if 既关心宏是否定义,又关心宏的逻辑的真假
#ifdef
#ifndef
仅仅关心宏是否被定义,不关心宏的逻辑真假

代码区分如下:

1
2
3
4
5
#if DEBUG

#elif PRERELEASE

#endif

至此,Configuration添加完成 。

分割图1