class ReactNativeUtil::Project

Constants

DEFAULT_DEPENDENCIES
Array<String>

Xcode projects from react-native that may be in the Libraries group

Attributes

app_name[RW]

Public Instance Methods

add_packager_script_from(react_project) click to toggle source

Adds the Start Packager script from the React.xcodeproj under node_modules to the main application target before deleting React.xcodeproj from the Libraries group. Adjusts paths in the script to account for the different project location. If the relevant build phase is not found, a warning is logged, and this step is skipped.

# File lib/react_native_util/project.rb, line 172
def add_packager_script_from(react_project)
  old_packager_phase = react_project.packager_phase
  unless old_packager_phase
    log 'Could not find packager build phase in React.xcodeproj. Skipping.'.yellow
    return
  end

  # location of project is different relative to packager script
  script = old_packager_phase.shell_script.gsub(%r{../scripts}, '../node_modules/react-native/scripts')

  phase = app_target.new_shell_script_build_phase old_packager_phase.name
  phase.shell_script = script

  # Move packager script to first position. This is independent of the
  # entire Xcode build process. As an optimization, the packager can
  # load its dependencies in parallel. This is the way it is on the
  # original React.xcodeproj.
  app_target.build_phases.delete phase
  app_target.build_phases.insert 0, phase
end
app_target(platform = :ios) click to toggle source
# File lib/react_native_util/project.rb, line 32
def app_target(platform = :ios)
  targets.find { |t| t.platform_name == platform && t.product_type == 'com.apple.product-type.application' }
end
dependencies() click to toggle source

A list of external dependencies from NPM requiring react-native link. @return [Array<String>] a list of NPM package names

# File lib/react_native_util/project.rb, line 125
def dependencies
  return [] if libraries_group.nil?

  dependency_paths.map do |path|
    # Map each path to a Pathname, expanding $(SRCROOT) or ${SRCROOT}
    # SRCROOT = location of the app project: ./ios
    Pathname.new path.gsub(/\$(\(SRCROOT\)|{SRCROOT})/, 'ios')
  end.select do |pathname|
    # Valid if any path component named node_modules
    pathname.each_filename do |path_component|
      break true if path_component == 'node_modules'

      false
    end
  end.map do |pathname|
    # Map each selected Pathname to the root immediately under node_modules
    node_modules_found = false
    pathname.each_filename do |path_component|
      break path_component if node_modules_found

      node_modules_found = path_component == 'node_modules'
      '' # In case node_modules is the last component
      # TODO: Then what? Shouldn't happen, of course....
    end
  end
end
dependency_paths() click to toggle source

Paths to Xcode projects in the Libraries group from external deps. @return [Array<String>] a list of absolute paths to Xcode projects

# File lib/react_native_util/project.rb, line 154
def dependency_paths
  return [] if libraries_group.nil?

  paths = libraries_group.children.reject { |c| DEFAULT_DEPENDENCIES.include?(c.name.sub(/\.xcodeproj$/, '')) }.map(&:path)
  paths.map { |p| File.expand_path p, File.join(Dir.pwd, 'ios') }
end
libraries_group() click to toggle source

A representation of the Libraries group (if any) from the Xcode project. @return the Libraries group

# File lib/react_native_util/project.rb, line 48
def libraries_group
  self['Libraries']
end
library_roots() click to toggle source
# File lib/react_native_util/project.rb, line 161
def library_roots
  libraries_group.children.map do |library|
    File.basename(library.path).sub(/\.xcodeproj$/, '')
  end
end
packager_phase() click to toggle source

Returns the original Start Packager build phase (from the React.xcodeproj under node_modules). This contains the original script. @return the packager build phase if found @return nil if not found

# File lib/react_native_util/project.rb, line 210
def packager_phase
  targets.first.build_phases.find { |p| p.name =~ /packager/i }
end
remove_libraries_from_target(target) click to toggle source
# File lib/react_native_util/project.rb, line 107
def remove_libraries_from_target(target)
  to_remove = target.frameworks_build_phase.files.select do |file|
    path = file.file_ref.pretty_print
    next false unless /^lib(.+)\.a$/.match?(path)

    path = path.sub(/-tvOS\.a$/, '.a')
    static_libs.include?(path)
  end

  log "Removing Libraries from #{target.name}" unless to_remove.empty?
  to_remove.each do |f|
    log " Removing #{f.file_ref.pretty_print}"
    target.frameworks_build_phase.remove_build_file f
  end
end
remove_libraries_group() click to toggle source

Remove the Libraries group from the xcodeproj in memory.

# File lib/react_native_util/project.rb, line 80
def remove_libraries_group
  # Remove links against these static libraries from all targets
  targets.each do |t|
    remove_libraries_from_target t
  end

  # Remove any unused projects from the Libraries group
  library_roots.each do |root|
    next unless targets_linking_with(root).empty?

    # Remove this lib from the Libraries group. Nothing is linking against it
    # anymore.
    child = libraries_group.children.find { |c| c.path =~ /#{root}\.xcodeproj/ }
    log "Removing #{root}.xcodeproj from Libraries group."
    child.remove_from_project
  end

  # Remove the Libraries group if it's empty. Or report that it's not.
  unless library_roots.empty?
    log 'Libraries group not empty. Not removing.'
    return
  end

  log 'Removing Libraries group.'
  libraries_group.remove_from_project
end
static_libs(platform = :ios) click to toggle source

All static libraries from the Libraries group @return [Array<String>] an array of filenames

# File lib/react_native_util/project.rb, line 195
def static_libs(platform = :ios)
  library_roots.map do |root|
    case platform
    when :tvos
      "lib#{root}-tvOS.a"
    else
      "lib#{root}.a"
    end
  end
end
targets_linking_with(root) click to toggle source
# File lib/react_native_util/project.rb, line 52
def targets_linking_with(root)
  targets_matching do |r|
    if root.respond_to?(:include?)
      root.include? r
    else
      log "r = #{r}, root = #{root}"
      r == root
    end
  end
end
targets_matching() { |matches| ... } click to toggle source
# File lib/react_native_util/project.rb, line 63
def targets_matching(&block)
  targets.reject do |target|
    file_refs = target.frameworks_build_phase.files.map(&:file_ref).reject(&:nil?).map(&:pretty_print)

    libs_from_libraries_group = file_refs.select do |lib|
      lib = lib.sub(/-tvOS/, '')
      matches = /^lib(.+)\.a$/.match lib
      next false unless matches

      yield matches[1]
    end

    libs_from_libraries_group.empty?
  end
end
test_target(platform = :ios) click to toggle source
# File lib/react_native_util/project.rb, line 36
def test_target(platform = :ios)
  targets.select(&:test_target_type?).select { |t| t.platform_name == platform }.first
end
validate_app_target!() click to toggle source

Validate an assumption about the project. TODO: Provide override option. @raise ConversionError if an application target is not found with the same name as the project.

# File lib/react_native_util/project.rb, line 42
def validate_app_target!
  raise ConversionError, "Unable to find application target in #{path}." if app_target.nil?
end