cocoapods-amimono 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +51 -2
- data/lib/cocoapods-amimono/gem_version.rb +1 -1
- data/lib/cocoapods-amimono/integrator.rb +49 -29
- data/lib/cocoapods-amimono/patcher.rb +41 -0
- data/lib/cocoapods_plugin.rb +5 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a607ef5c8f40f9e3573b195af6e60a5e0467054
|
4
|
+
data.tar.gz: 8da7473fed96d2e25e069b70c6228a1c6fc3ac05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93182f0c82f6a5cf9ab1f587f3ca5fceeaa90f58a3b76c78939bc95d685f5d0d0e92e89dc6c281ae37588a4a573e61f8767491ede509a7f3b269c43aad0bb65f
|
7
|
+
data.tar.gz: 13feccb0c3b83750b6a05c63f6fa2858f1f8de236b9ededca0e305523a16e187ba7a0480e2b64ab1c9fd79ab1b8a5c000b9dc66777665956ea174f6738d7c953
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,60 @@
|
|
1
1
|
# cocoapods-amimono
|
2
2
|
|
3
|
+
<p align="center">
|
4
|
+
<img src="https://dl.dropboxusercontent.com/u/12352209/GitHub/amimono.gif" alt="amimono"/>
|
5
|
+
</p>
|
6
|
+
|
3
7
|
Move all dynamic frameworks symbols into the main executable.
|
4
8
|
|
9
|
+
## Why would you want this plugin in your Podfile?
|
10
|
+
|
11
|
+
Apple introduced dynamic linking on iOS 8 alongside with Swift. Shortly after, this was adopted by CocoaPods as a requirement to use Pods that contain Swift, because Xcode can't use static libraries with Swift.
|
12
|
+
|
13
|
+
On iOS 9.1, a dyld crash affected the vast majority of apps that used a high number of dynamic frameworks. You can learn more about the issue on [artsy/eigen#1246](https://github.com/artsy/eigen/issues/1246). Although the issue was fixed on iOS 9.3.2, it was clear that having a high number of dynamic frameworks was not a good idea. During WWDC 2016, someone asked what would be the optimal number of dynamic frameworks on an iOS application and we got the following response:
|
14
|
+
|
15
|
+
> Apple advises to use about half a dozen dynamic frameworks in an app. Hard to achieve with external & internal deps.
|
16
|
+
> -- from [Twitter](https://twitter.com/arekholko/status/743135179514978304)
|
17
|
+
|
18
|
+
This is hardly an option for some. If you think you might be in that group, then continue reading.
|
19
|
+
|
20
|
+
## What is this plugin doing?
|
21
|
+
|
22
|
+
This plugin is based on [dyld-image-loading-performance](https://github.com/stepanhruda/dyld-image-loading-performance). In a nutshell, it copies all symbols of your CocoaPods dependencies into your main app executable, so the dynamic linker doesn't have to load the frameworks. You can verify this yourself by enabling
|
23
|
+
|
24
|
+
![log_setting_xcode.png](https://dl.dropboxusercontent.com/u/12352209/GitHub/log_setting_xcode.png)
|
25
|
+
|
26
|
+
and looking at the log output you shouldn't find any `dlopen` call of your CocoaPods frameworks.
|
27
|
+
|
28
|
+
## Limitations
|
29
|
+
|
30
|
+
Currently this plugin has the following limitations:
|
31
|
+
|
32
|
+
* You will have modify your `post_install` hook. This is necessary because the CocoaPods plugin API currently doesn't offer everything that the gem needs.
|
33
|
+
* Only dependencies compiled from source will work. This means dependencies with bundled binaries (like vendored static frameworks) won't work. You will have to add these manually to your Xcode project.
|
34
|
+
|
5
35
|
## Installation
|
6
36
|
|
7
|
-
|
37
|
+
```bash
|
38
|
+
gem install cocoapods-amimono
|
39
|
+
````
|
8
40
|
|
9
41
|
## Usage
|
10
42
|
|
11
|
-
|
43
|
+
Add the following to your Podfile:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
plugin 'cocoapods-amimono'
|
47
|
+
```
|
48
|
+
|
49
|
+
Add the following to your `post_install` hook:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
post_install do |installer|
|
53
|
+
require 'cocoapods-amimono/patcher'
|
54
|
+
Amimono::Patcher.patch_copy_resources_script(installer: installer)
|
55
|
+
...
|
56
|
+
```
|
57
|
+
|
58
|
+
## Example project
|
59
|
+
|
60
|
+
[Here](https://github.com/Ruenzuo/cocoapods-amimono-example).
|
@@ -1,9 +1,33 @@
|
|
1
1
|
module Amimono
|
2
2
|
class Integrator
|
3
3
|
|
4
|
+
FILELIST_SCRIPT = <<-SCRIPT.strip_heredoc
|
5
|
+
#!/usr/bin/ruby
|
6
|
+
intermediates_directory = ENV['OBJROOT']
|
7
|
+
configuration = ENV['CONFIGURATION']
|
8
|
+
platform = ENV['EFFECTIVE_PLATFORM_NAME']
|
9
|
+
archs = ENV['ARCHS']
|
10
|
+
target_name = ENV['TARGET_NAME']
|
11
|
+
|
12
|
+
archs.split(" ").each do |architecture|
|
13
|
+
Dir.chdir("\#{intermediates_directory}/Pods.build") do
|
14
|
+
filelist = ""
|
15
|
+
%s.each do |dependency|
|
16
|
+
Dir.glob("\#{configuration}\#{platform}/\#{dependency}.build/Objects-normal/\#{architecture}/*.o") do |object_file|
|
17
|
+
next if ["Pods-\#{target_name}-dummy", "Pods_\#{target_name}_vers"].any? { |dummy_object| object_file.include? dummy_object }
|
18
|
+
filelist += File.absolute_path(object_file) + "\\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
File.write("\#{configuration}\#{platform}-\#{architecture}.objects.filelist", filelist)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
SCRIPT
|
25
|
+
|
26
|
+
AMIMONO_FILELIST_BUILD_PHASE = '[Amimono] Create filelist per architecture'
|
27
|
+
|
4
28
|
def update_xcconfigs(aggregated_target_sandbox_path:)
|
5
29
|
path = aggregated_target_sandbox_path
|
6
|
-
archs = ['armv7', 'arm64', 'i386', 'x86_64']
|
30
|
+
archs = ['armv7', 'armv7s', 'arm64', 'i386', 'x86_64']
|
7
31
|
# Find all xcconfigs for the aggregated target
|
8
32
|
Dir.entries(path).select { |entry| entry.end_with? 'xcconfig' }.each do |entry|
|
9
33
|
full_path = path + entry
|
@@ -21,38 +45,34 @@ module Amimono
|
|
21
45
|
|
22
46
|
def update_build_phases(aggregated_target:)
|
23
47
|
user_project = aggregated_target.user_project
|
24
|
-
# Remove the `Embed Pods Frameworks` build phase
|
25
48
|
application_target = user_project.targets.find { |target| target.product_type.end_with? 'application' }
|
26
|
-
|
27
|
-
|
28
|
-
#
|
29
|
-
|
49
|
+
# Remove the `Embed Pods Frameworks` build phase
|
50
|
+
remove_embed_pods_frameworks(application_target: application_target)
|
51
|
+
# Create or update [Amimono] build phase
|
52
|
+
create_or_update_amimono_phase(application_target: application_target, phase_name: AMIMONO_FILELIST_BUILD_PHASE, script: generate_filelist_script(aggregated_target: aggregated_target))
|
30
53
|
user_project.save
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def remove_embed_pods_frameworks(application_target:)
|
59
|
+
embed_pods_frameworks_build_phase = application_target.build_phases.find { |build_phase| build_phase.display_name.include? 'Embed Pods Frameworks' }
|
60
|
+
return if embed_pods_frameworks_build_phase.nil?
|
61
|
+
embed_pods_frameworks_build_phase.remove_from_project
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_or_update_amimono_phase(application_target:, phase_name:, script:)
|
65
|
+
amimono_filelist_build_phase = application_target.build_phases.find { |build_phase| build_phase.display_name.include? phase_name } || application_target.new_shell_script_build_phase(phase_name)
|
66
|
+
amimono_filelist_build_phase.shell_path = '/usr/bin/ruby'
|
67
|
+
amimono_filelist_build_phase.shell_script = script
|
68
|
+
application_target.build_phases.insert(1, amimono_filelist_build_phase)
|
35
69
|
application_target.build_phases.uniq!
|
36
|
-
shell_build_phase.shell_path = '/usr/bin/ruby'
|
37
|
-
shell_build_phase.shell_script = <<-SCRIPT.strip_heredoc
|
38
|
-
#!/usr/bin/ruby
|
39
|
-
intermediates_directory = ENV['OBJROOT']
|
40
|
-
configuration = ENV['CONFIGURATION']
|
41
|
-
platform = ENV['EFFECTIVE_PLATFORM_NAME']
|
42
|
-
archs = ENV['ARCHS']
|
43
|
-
|
44
|
-
archs.split(" ").each do |architecture|
|
45
|
-
Dir.chdir("\#{intermediates_directory}/Pods.build") do
|
46
|
-
filelist = ""
|
47
|
-
Dir.glob("\#{configuration}\#{platform}/*.build/Objects-normal/\#{architecture}/*.o") do |object_file|
|
48
|
-
filelist += File.absolute_path(object_file) + "\\n"
|
49
|
-
end
|
50
|
-
File.write("\#{configuration}\#{platform}-\#{architecture}.objects.filelist", filelist)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
SCRIPT
|
54
|
-
user_project.save
|
55
70
|
end
|
56
71
|
|
72
|
+
def generate_filelist_script(aggregated_target:)
|
73
|
+
dependencies = aggregated_target.specs.map(&:name).reject { |dependency| dependency.include? '/'}
|
74
|
+
puts "[Amimono] #{dependencies.count} dependencies found"
|
75
|
+
FILELIST_SCRIPT % dependencies.to_s
|
76
|
+
end
|
57
77
|
end
|
58
78
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Amimono
|
2
|
+
# This class will patch your project's copy resources script to match the one that would be
|
3
|
+
# generated as if the `use_frameworks!` flag wouldn't be there
|
4
|
+
class Patcher
|
5
|
+
def self.patch_copy_resources_script(installer:)!
|
6
|
+
aggregated_target = installer.aggregate_targets.first
|
7
|
+
project = installer.sandbox.project
|
8
|
+
path = aggregated_target.copy_resources_script_path
|
9
|
+
resources = resources_by_config(aggregated_target: aggregated_target, project: project)
|
10
|
+
generator = Pod::Generator::CopyResourcesScript.new(resources, aggregated_target.platform)
|
11
|
+
generator.save_as(path)
|
12
|
+
puts "[Amimono] Copy resources script patched"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Copied over from https://github.com/CocoaPods/CocoaPods/blob/master/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb#L115-L131
|
18
|
+
# with some modifications to this particular use case
|
19
|
+
def self.resources_by_config(aggregated_target:, project:)
|
20
|
+
library_targets = aggregated_target.pod_targets.reject do |pod_target|
|
21
|
+
# This reject doesn't matter much anymore. We have to process all targets because
|
22
|
+
# every single one requires frameworks and this workaround doesn't work with Pods
|
23
|
+
# that contains binaries
|
24
|
+
!pod_target.should_build?
|
25
|
+
end
|
26
|
+
aggregated_target.user_build_configurations.keys.each_with_object({}) do |config, resources_by_config|
|
27
|
+
resources_by_config[config] = library_targets.flat_map do |library_target|
|
28
|
+
next [] unless library_target.include_in_build_config?(aggregated_target.target_definition, config)
|
29
|
+
resource_paths = library_target.file_accessors.flat_map do |accessor|
|
30
|
+
accessor.resources.flat_map { |res| res.relative_path_from(project.path.dirname) }
|
31
|
+
end
|
32
|
+
resource_bundles = library_target.file_accessors.flat_map do |accessor|
|
33
|
+
accessor.resource_bundles.keys.map { |name| "#{library_target.configuration_build_dir}/#{name.shellescape}.bundle" }
|
34
|
+
end
|
35
|
+
# The `bridge_support_file` has been removed from this part
|
36
|
+
(resource_paths + resource_bundles).uniq
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/cocoapods_plugin.rb
CHANGED
@@ -3,6 +3,9 @@ require 'cocoapods-amimono/integrator'
|
|
3
3
|
|
4
4
|
Pod::HooksManager.register('cocoapods-amimono', :post_install) do |installer_context|
|
5
5
|
# Find the aggregated target
|
6
|
+
# This is probably wrong, all agregated targets are prefixed by 'Pods-'
|
7
|
+
# but this works for now because find will return the first one
|
8
|
+
# which is usually the app target
|
6
9
|
pods_target = installer_context.umbrella_targets.find do |target|
|
7
10
|
target.cocoapods_target_label.include? 'Pods'
|
8
11
|
end
|
@@ -12,5 +15,7 @@ Pod::HooksManager.register('cocoapods-amimono', :post_install) do |installer_con
|
|
12
15
|
|
13
16
|
integrator = Amimono::Integrator.new
|
14
17
|
integrator.update_xcconfigs(aggregated_target_sandbox_path: path)
|
18
|
+
puts "[Amimono] xcconfigs updated with filelist"
|
15
19
|
integrator.update_build_phases(aggregated_target: pods_target)
|
20
|
+
puts "[Amimono] Build phases updated"
|
16
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cocoapods-amimono
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renzo Crisostomo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07
|
11
|
+
date: 2016-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- lib/cocoapods-amimono/command/amimono.rb
|
60
60
|
- lib/cocoapods-amimono/gem_version.rb
|
61
61
|
- lib/cocoapods-amimono/integrator.rb
|
62
|
+
- lib/cocoapods-amimono/patcher.rb
|
62
63
|
- lib/cocoapods_plugin.rb
|
63
64
|
- spec/command/amimono_spec.rb
|
64
65
|
- spec/spec_helper.rb
|