cocoapods-amimono 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|