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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c802deb44fc7227e5a1ca4f4fb266f7ff51d06bc
4
- data.tar.gz: fb88a7712cd35bf6f3fc1b468f682e45c0b9e07e
3
+ metadata.gz: 7a607ef5c8f40f9e3573b195af6e60a5e0467054
4
+ data.tar.gz: 8da7473fed96d2e25e069b70c6228a1c6fc3ac05
5
5
  SHA512:
6
- metadata.gz: 96f17037f27c9f6fac1c0d7594eb78f1aa0d03b68c9a2dc2ce88d5651581e45ffa60dda7ffdbf4a28ddf23c11cc1d0ff5c1fb7c29b077b3bab3e2491051d9b62
7
- data.tar.gz: aca7d993ad1c6b6cd26cf629f6d0f49550c33543143fe2a8822d93a353cb121942554aeb633aa778e991348867d2f2f6cd888ee7a985a8ed9997aa1662241e4a
6
+ metadata.gz: 93182f0c82f6a5cf9ab1f587f3ca5fceeaa90f58a3b76c78939bc95d685f5d0d0e92e89dc6c281ae37588a4a573e61f8767491ede509a7f3b269c43aad0bb65f
7
+ data.tar.gz: 13feccb0c3b83750b6a05c63f6fa2858f1f8de236b9ededca0e305523a16e187ba7a0480e2b64ab1c9fd79ab1b8a5c000b9dc66777665956ea174f6738d7c953
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cocoapods-amimono (0.0.1)
4
+ cocoapods-amimono (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- $ gem install cocoapods-amimono
37
+ ```bash
38
+ gem install cocoapods-amimono
39
+ ````
8
40
 
9
41
  ## Usage
10
42
 
11
- $ plugin 'cocoapods-amimono'
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,3 +1,3 @@
1
1
  module CocoapodsAmimono
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
- embed_pods_frameworks_build_phase = application_target.build_phases.find { |build_phase| build_phase.display_name.eql? '[CP] Embed Pods Frameworks' }
27
- embed_pods_frameworks_build_phase.remove_from_project
28
- # Check if [Amimono] phase already exist
29
- amimono_build_phase = application_target.build_phases.find { |build_phase| build_phase.display_name.include? '[Amimono]' }
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
- return unless amimono_build_phase.nil?
32
- # Add new shell
33
- shell_build_phase = application_target.new_shell_script_build_phase '[Amimono] Create filelist per architecture'
34
- application_target.build_phases.insert(1, shell_build_phase)
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
@@ -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.1
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-31 00:00:00.000000000 Z
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