antenna-ota 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2b59a0fbdec9597247581376b8a5b085ed25b408
4
+ data.tar.gz: f05872512ebae67437c2fd558289bebddf511866
5
+ SHA512:
6
+ metadata.gz: 70591554210189f8cf4b3d9865554018ee39f7f4dad7674a475913013ddb39b5ca54b5ee9018ec95ef31433939f48c579d9689185d0f42087b34199152768845
7
+ data.tar.gz: ed3db2582dcb978b6f8b606517555a876a8effe531870fff371aa006159aa2bec2344d36e72ecc842cf503e5dae7808f07ab1c39e711364d34761681e6697928
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in antenna-ota.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Tobias Kremer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # Antenna
2
+
3
+ Antenna aims to take the pain out of creating and distributing all the necessary files for Enterprise iOS over-the-air distribution. It generates the mandatory XML manifest, app icons and an HTML file, automatically extracting all the needed information from the specified `.ipa` file, and uploads everything via a distribution method of your choice (currently only S3 is supported, but you're encouraged to create other storage backends). The result is a (signed S3) URL, which you may then send to your clients, so they can easily install your app from Mobile Safari with just one tap.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install antenna-ota
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Antenna adds the `antenna` command to your PATH:
14
+
15
+ ```bash
16
+ $ antenna
17
+
18
+ Antenna
19
+
20
+ Painless iOS over-the-air enterprise distribution
21
+
22
+ Commands:
23
+ help Display global or [command] help documentation
24
+ s3 Distribute .ipa file over Amazon S3
25
+
26
+ Global Options:
27
+ --verbose
28
+ -h, --help Display help documentation
29
+ -v, --version Display version information
30
+ -t, --trace Display backtrace when an error occurs
31
+ ```
32
+
33
+ ## Example
34
+
35
+ Create a new S3 bucket called `antenna-ota` on Amazon's `eu-central-1` S3 cluster and upload OverTheAir.ipa:
36
+
37
+ ```bash
38
+ $ antenna s3 -a <YOUR-S3-ACCESS-KEY> -s <YOUR-S3-SECRET-KEY> --file OverTheAir.ipa --region eu-central-1 --create --bucket antenna-ota
39
+ Distributing OverTheAir.ipa ...
40
+ Distributing OverTheAir.png ...
41
+ Distributing OverTheAir.plist ...
42
+ Distributing OverTheAir.html ...
43
+ https://antenna-ota.s3.eu-central-1.amazonaws.com/OverTheAir.html?<...signing-parameters...>
44
+ ```
45
+
46
+ The resulting URL leads to an installation page like the following and can be distributed to your users for installation. The meta-data and app-icon is automatically extracted from the given .ipa file.
47
+
48
+ ![Installation site](https://raw.githubusercontent.com/soulchild/antenna/master/assets/example-installation.png)
49
+
50
+ *Note:* App icons in any .ipa file are converted from PNG to [Apple's CgBI file format](http://iphonedevwiki.net/index.php/CgBI_file_format) and therefore not viewable in most applications, including Chrome and Firefox. Apple applications like (Mobile) Safari or Preview.app know how to handle the format though.
51
+
52
+ ## Author
53
+
54
+ Tobi Kremer ([soulchild](https://www.github.com/soulchild))
55
+
56
+ Inspired by Mattt Thompson's [iOS toolchain](https://github.com/nomad).
57
+
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/soulchild/antenna).
61
+
62
+ ## License
63
+
64
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'antenna/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "antenna-ota"
8
+ spec.version = Antenna::VERSION
9
+ spec.authors = ["Tobi Kremer"]
10
+ spec.email = ["tobias.kremer@gmail.com"]
11
+ spec.summary = %q{Painless iOS over-the-air enterprise distribution}
12
+ spec.description = %q{Antenna aims to take the pain out of creating and distributing all the necessary files for Enterprise iOS over-the-air distribution. It generates the mandatory XML manifest, app icons and an HTML file, automatically extracting all the needed information from the specified .ipa file.}
13
+ spec.homepage = "https://www.github.com/soulchild/antenna"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.10"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "aws-sdk", '~> 2.0', '>= 2.0.0'
25
+ spec.add_dependency "commander", "~> 4.3"
26
+ spec.add_dependency "highline", '~> 1.7', '>= 1.7.2'
27
+ spec.add_dependency "CFPropertyList", '~> 2.3', '>= 2.3.0'
28
+ spec.add_dependency "rubyzip", '~> 1.0', '>= 1.0.0'
29
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "awesome"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'antenna'
5
+
6
+ program :name, 'Antenna'
7
+ program :version, Antenna::VERSION
8
+ program :description, 'Painless iOS over-the-air enterprise distribution'
9
+
10
+ program :help, 'Author', 'Tobi Kremer <tobias@funkreich.de>'
11
+ program :help, 'Website', 'https://www.github.com/soulchild/antenna'
12
+ program :help_formatter, :compact
13
+
14
+ # global_option('--verbose') { $verbose = true }
15
+
16
+ default_command :help
17
+
18
+ require 'antenna/commands'
@@ -0,0 +1 @@
1
+ require "antenna/version"
@@ -0,0 +1,66 @@
1
+ require 'distributor'
2
+ require 'distributor/s3'
3
+
4
+ command :s3 do |c|
5
+ c.name = "s3"
6
+ c.syntax = "antenna s3 [options]"
7
+ c.summary = "Distribute .ipa file over Amazon S3"
8
+
9
+ c.example 'Distribute "awesome.ipa" to S3 bucket "bucket_name"', 'antenna s3 --file ./awesome.ipa -a access_key_id -s secret_access_key --create -b bucket_name'
10
+
11
+ c.option '-f', '--file FILE', '.ipa file to distribute (searches current directory for .ipa files if not specified)'
12
+ c.option '-a', '--access-key-id ACCESS_KEY_ID', 'S3 access key ID'
13
+ c.option '-s', '--secret-access-key SECRET_ACCESS_KEY', 'S3 secret access key'
14
+ c.option '-b', '--bucket BUCKET', 'S3 bucket name'
15
+ c.option '--[no-]create', "(Don't) create bucket if it doesn't already exist"
16
+ c.option '-r', '--region REGION', "AWS region (optional, defaults to us-east-1)"
17
+ c.option '-e', '--endpoint ENDPOINT', "S3 endpoint (optional, e.g. https://mys3.example.com)"
18
+ c.option '-x', '--expires EXPIRES', "Expiration of URLs in seconds (optional, e.g. 86400 = one day)"
19
+ c.option '-i', '--base BASE', "Base filename (optional, defaults to IPA filename without .ipa extension)"
20
+ c.option '--acl ACL', "Permissions for uploaded files. Must be one of: public_read, private, public_read_write, authenticated_read (optional, defaults to private)"
21
+
22
+ c.action do |args, options|
23
+ determine_file! unless @file = options.file
24
+ say_error "Missing .ipa file" and abort unless @file and File.exist?(@file)
25
+
26
+ determine_access_key_id! unless @access_key_id = options.access_key_id
27
+ say_error "Missing S3 access key ID" and abort unless @access_key_id
28
+
29
+ determine_secret_access_key! unless @secret_access_key = options.secret_access_key
30
+ say_error "Missing S3 secret access key" and abort unless @secret_access_key
31
+
32
+ determine_bucket! unless @bucket = options.bucket
33
+ say_error "Missing S3 bucket name" and abort unless @bucket
34
+
35
+ @endpoint = options.endpoint
36
+ unless @endpoint
37
+ determine_region! unless @region = options.region
38
+ say_error "Missing either S3 region or endpoint" and abort unless @region
39
+ end
40
+
41
+ s3 = Antenna::Distributor::S3.new(@access_key_id, @secret_access_key, @region, @endpoint)
42
+ distributor = Antenna::Distributor.new(s3)
43
+ puts distributor.distribute @file, { :bucket => @bucket, :create => !!options.create, :expire => options.expires, :acl => @acl, :base => options.base }
44
+ end
45
+
46
+ private
47
+
48
+ def determine_access_key_id!
49
+ @access_key_id ||= ENV['AWS_ACCESS_KEY_ID']
50
+ @access_key_id ||= ask "S3 access key ID:"
51
+ end
52
+
53
+ def determine_secret_access_key!
54
+ @secret_access_key ||= ENV['AWS_SECRET_ACCESS_KEY']
55
+ @secret_access_key ||= ask "S3 secret access key:"
56
+ end
57
+
58
+ def determine_bucket!
59
+ @bucket ||= ENV['AWS_BUCKET']
60
+ @bucket ||= ask "S3 bucket name:"
61
+ end
62
+
63
+ def determine_region!
64
+ @region ||= ENV['AWS_REGION']
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ $:.push File.expand_path('../', __FILE__)
2
+
3
+ require 'command/s3'
4
+
5
+ private
6
+
7
+ def determine_file!
8
+ files = Dir['*.ipa']
9
+ @file ||= case files.length
10
+ when 0 then nil
11
+ when 1 then files.first
12
+ else
13
+ @file = choose "Select an .ipa File:", *files
14
+ end
15
+ puts "Found ipa file #{@file}" if @file
16
+ end
@@ -0,0 +1,74 @@
1
+ require 'antenna/ipa'
2
+ require 'antenna/manifest'
3
+ require 'antenna/html'
4
+
5
+ module Antenna
6
+ class Distributor
7
+ def initialize(distributor)
8
+ @distributor = distributor
9
+ end
10
+
11
+ def distribute(ipa_file, options = {})
12
+ base_filename = options[:base] || File.basename(ipa_file, ".ipa")
13
+
14
+ # Let distributor set things up (if necessary)
15
+ @distributor.setup(ipa_file, options) if @distributor.respond_to?(:setup)
16
+
17
+ # Distribute IPA
18
+ ipa = process_ipa(ipa_file)
19
+ ipa_url = @distributor.distribute(
20
+ ipa.input_stream.read,
21
+ "#{base_filename}.ipa",
22
+ "application/octet-stream",
23
+ )
24
+
25
+ # Distribute App Icon
26
+ if app_icon = process_app_icon(ipa)
27
+ app_icon_url = @distributor.distribute(
28
+ app_icon,
29
+ "#{base_filename}.png",
30
+ "image/png",
31
+ )
32
+ end
33
+
34
+ # Distribute Manifest
35
+ manifest = build_manifest(ipa, ipa_url, app_icon_url)
36
+ manifest_url = @distributor.distribute(
37
+ manifest.to_s,
38
+ "#{base_filename}.plist",
39
+ "text/xml",
40
+ )
41
+
42
+ # Distribute HTML
43
+ html = build_html(ipa, manifest_url, app_icon_url)
44
+ html_url = @distributor.distribute(
45
+ html.to_s,
46
+ "#{base_filename}.html",
47
+ "text/html",
48
+ )
49
+
50
+ # Let distributor clean things up (if necessary)
51
+ @distributor.teardown if @distributor.respond_to?(:teardown)
52
+
53
+ return html_url
54
+ end
55
+
56
+ private
57
+
58
+ def process_ipa(ipa_file)
59
+ Antenna::IPA.new(ipa_file)
60
+ end
61
+
62
+ def process_app_icon(ipa)
63
+ ipa.bundle_icon_files["57x57@2x"] || ipa.bundle_icon_files["60x60@2x"] || ipa.bundle_icon_files["60x60@3x"]
64
+ end
65
+
66
+ def build_manifest(ipa, ipa_url, app_icon_url)
67
+ Antenna::Manifest.new(ipa_url, ipa.info_plist, app_icon_url)
68
+ end
69
+
70
+ def build_html(ipa, manifest_url, app_icon_url)
71
+ Antenna::HTML.new(ipa.info_plist, manifest_url, app_icon_url)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,42 @@
1
+ require 'aws-sdk'
2
+
3
+ module Antenna
4
+ class Distributor::S3
5
+ def initialize(access_key_id, secret_access_key, region, endpoint = nil)
6
+ options = {
7
+ :access_key_id => access_key_id,
8
+ :secret_access_key => secret_access_key,
9
+ :region => region || "us-east-1",
10
+ }
11
+ options[:endpoint] = endpoint if endpoint
12
+ @s3 = Aws::S3::Resource.new(options)
13
+ end
14
+
15
+ def setup(ipa_file, options = {})
16
+ @options = options
17
+ @options[:expire] = @options[:expire].to_i || 86400
18
+ @options[:acl] ||= "private"
19
+
20
+ if @options[:create]
21
+ puts "Creating bucket #{@options[:bucket]} with ACL #{@options[:acl]}..."
22
+
23
+ @s3.create_bucket({
24
+ :bucket => @options[:bucket],
25
+ :acl => @options[:acl],
26
+ })
27
+ end
28
+ end
29
+
30
+ def distribute(data, filename, content_type)
31
+ puts "Distributing #{filename} ..."
32
+
33
+ object = @s3.bucket(@options[:bucket]).put_object({
34
+ :key => filename,
35
+ :content_type => content_type,
36
+ :body => data,
37
+ })
38
+
39
+ URI.parse(object.presigned_url(:get, { :expires_in => @options[:expire] }))
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,63 @@
1
+ require 'erb'
2
+
3
+ module Antenna
4
+ class HTML
5
+ include ERB::Util
6
+
7
+ attr_accessor :info_plist, :manifest_url, :display_image_url, :need_shine
8
+
9
+ def initialize(info_plist, manifest_url, display_image_url)
10
+ @info_plist, @manifest_url, @display_image_url = info_plist, manifest_url, display_image_url
11
+ end
12
+
13
+ def template
14
+ <<-EOF
15
+ <!doctype html>
16
+ <html>
17
+ <head>
18
+ <title><%= @info_plist.bundle_display_name %> v<%= @info_plist.bundle_short_version %> (<%= @info_plist.bundle_version %>)</title>
19
+ <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
20
+ <style type="text/css">
21
+ body { font-family: Helvetica, Arial, sans-serif; text-align: center; color: #444; font-size: 18px; }
22
+ img { display: block; margin: 1em auto; border: none; width: 120px; height: 120px; border-radius: 20px; }
23
+ .btn, a.btn, a.btn:visited, a.btn:hover, a.btn:link {
24
+ display: inline-block;
25
+ border-radius: 3px;
26
+ background-color: #0095c8;
27
+ color: white;
28
+ padding: .8em 1em;
29
+ text-decoration: none;
30
+ }
31
+ a.btn:hover {
32
+ background-color: #00bbfb;
33
+ color: white;
34
+ }
35
+ p {
36
+ color: #999
37
+ }
38
+ </style>
39
+ </head>
40
+ <body>
41
+ <h1><%= @info_plist.bundle_display_name %></h1>
42
+ <h2><%= @info_plist.bundle_short_version %> (<%= @info_plist.bundle_version %>)</h2>
43
+ <% if @display_image_url %>
44
+ <a href="itms-services://?action=download-manifest&amp;url=<%= u(@manifest_url) %>">
45
+ <img src="<%= @display_image_url %>">
46
+ </a>
47
+ <% end %>
48
+ <a href="itms-services://?action=download-manifest&amp;url=<%= u(@manifest_url) %>" class="btn">Tap to install</a>
49
+ <% if @info_plist.bundle_minimum_os_version %>
50
+ <p class="comment">
51
+ This app requires iOS <%= @info_plist.bundle_minimum_os_version %> or higher.
52
+ </p>
53
+ <% end %>
54
+ </body>
55
+ </html>
56
+ EOF
57
+ end
58
+
59
+ def to_s
60
+ ERB.new(template).result(binding)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
1
+ require "CFPropertyList"
2
+
3
+ module Antenna
4
+ class InfoPlist
5
+ attr_accessor :bundle_display_name, :bundle_short_version, :bundle_identifier, :bundle_version, :bundle_icon_filenames, :bundle_minimum_os_version
6
+
7
+ def initialize(data)
8
+ infoplist = CFPropertyList::List.new(
9
+ :data => data,
10
+ :format => CFPropertyList::List::FORMAT_BINARY
11
+ )
12
+ infoplist_data = CFPropertyList.native_types(infoplist.value)
13
+
14
+ @bundle_display_name = infoplist_data["CFBundleDisplayName"] || infoplist_data["CFBundleName"]
15
+ @bundle_identifier = infoplist_data["CFBundleIdentifier"]
16
+ @bundle_short_version = infoplist_data["CFBundleShortVersionString"]
17
+ @bundle_version = infoplist_data["CFBundleVersion"]
18
+ @bundle_minimum_os_version = infoplist_data["MinimumOSVersion"]
19
+
20
+ icons = infoplist_data["CFBundleIcons"]
21
+ if icons
22
+ primary_icon = icons["CFBundlePrimaryIcon"]
23
+ if primary_icon
24
+ @bundle_icon_filenames = primary_icon["CFBundleIconFiles"]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ require "zip"
2
+ require "zip/filesystem"
3
+ require "antenna/infoplist"
4
+
5
+ module Antenna
6
+ class IPA
7
+ attr_accessor :filename, :app_name, :info_plist, :bundle_icon_files
8
+
9
+ def initialize(filename)
10
+ @filename = filename
11
+ @bundle_icon_files = {}
12
+
13
+ Zip::File.open(filename) do |zipfile|
14
+ zipfile.dir.entries("Payload").each do |entry|
15
+ # Find app name
16
+ if entry =~ /.app$/
17
+ app_entry = zipfile.find_entry("Payload/#{entry}")
18
+ if app_entry
19
+ @app_name = entry
20
+
21
+ # Find and parse Info.plist
22
+ infoplist_entry = zipfile.find_entry("Payload/#{@app_name}/Info.plist")
23
+ if infoplist_entry
24
+ infoplist_data = infoplist_entry.get_input_stream.read
25
+ @info_plist = Antenna::InfoPlist.new(infoplist_data)
26
+ break
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ say "Info.plist not found in #{filename}" and abort unless @info_plist
33
+
34
+ # Extract main icon files
35
+ @info_plist.bundle_icon_filenames.each do |icon|
36
+ icon_glob = "Payload/#{@app_name}/#{icon}*.png"
37
+ zipfile.glob(icon_glob).each do |entry|
38
+ (width, height, resolution) = entry.to_s.scan(/(\d+)x(\d+)@(\d+)x\.png$/).flatten
39
+ if width and height and resolution
40
+ key = "#{width}x#{height}@#{resolution}x"
41
+ @bundle_icon_files[key] = entry.get_input_stream.read
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def input_stream
49
+ File.open(@filename, "r")
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,60 @@
1
+ require 'erb'
2
+
3
+ module Antenna
4
+ class Manifest
5
+ include ERB::Util
6
+
7
+ attr_accessor :info_plist, :ipa_url, :display_image_url, :need_shine
8
+
9
+ def initialize(ipa_url, info_plist, display_image_url)
10
+ @ipa_url, @info_plist, @display_image_url = ipa_url, info_plist, display_image_url
11
+ end
12
+
13
+ def template
14
+ <<-EOF
15
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
16
+ <plist version="1.0">
17
+ <dict>
18
+ <key>items</key>
19
+ <array>
20
+ <dict>
21
+ <key>assets</key>
22
+ <array>
23
+ <dict>
24
+ <key>kind</key>
25
+ <string>software-package</string>
26
+ <key>url</key>
27
+ <string><%= h(@ipa_url) %></string>
28
+ </dict>
29
+ <dict>
30
+ <key>kind</key>
31
+ <string>display-image</string>
32
+ <key>needs-shine</key>
33
+ <false/>
34
+ <key>url</key>
35
+ <string><%= h(@display_image_url) %></string>
36
+ </dict>
37
+ </array>
38
+ <key>metadata</key>
39
+ <dict>
40
+ <key>bundle-identifier</key>
41
+ <string><%= @info_plist.bundle_identifier %></string>
42
+ <key>bundle-version</key>
43
+ <string><%= @info_plist.bundle_short_version %></string>
44
+ <key>kind</key>
45
+ <string>software</string>
46
+ <key>title</key>
47
+ <string><%= @info_plist.bundle_display_name %></string>
48
+ </dict>
49
+ </dict>
50
+ </array>
51
+ </dict>
52
+ </plist>
53
+ EOF
54
+ end
55
+
56
+ def to_s
57
+ ERB.new(template).result(binding)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,3 @@
1
+ module Antenna
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,190 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: antenna-ota
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tobi Kremer
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.0.0
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '2.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: commander
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '4.3'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '4.3'
75
+ - !ruby/object:Gem::Dependency
76
+ name: highline
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.7'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.7.2
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '1.7'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.7.2
95
+ - !ruby/object:Gem::Dependency
96
+ name: CFPropertyList
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '2.3'
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 2.3.0
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '2.3'
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: 2.3.0
115
+ - !ruby/object:Gem::Dependency
116
+ name: rubyzip
117
+ requirement: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - "~>"
120
+ - !ruby/object:Gem::Version
121
+ version: '1.0'
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.0.0
125
+ type: :runtime
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 1.0.0
135
+ description: Antenna aims to take the pain out of creating and distributing all the
136
+ necessary files for Enterprise iOS over-the-air distribution. It generates the mandatory
137
+ XML manifest, app icons and an HTML file, automatically extracting all the needed
138
+ information from the specified .ipa file.
139
+ email:
140
+ - tobias.kremer@gmail.com
141
+ executables:
142
+ - antenna
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - Gemfile
148
+ - LICENSE.txt
149
+ - README.md
150
+ - Rakefile
151
+ - antenna.gemspec
152
+ - assets/example-installation.png
153
+ - bin/console
154
+ - bin/setup
155
+ - exe/antenna
156
+ - lib/antenna.rb
157
+ - lib/antenna/command/s3.rb
158
+ - lib/antenna/commands.rb
159
+ - lib/antenna/distributor.rb
160
+ - lib/antenna/distributor/s3.rb
161
+ - lib/antenna/html.rb
162
+ - lib/antenna/infoplist.rb
163
+ - lib/antenna/ipa.rb
164
+ - lib/antenna/manifest.rb
165
+ - lib/antenna/version.rb
166
+ homepage: https://www.github.com/soulchild/antenna
167
+ licenses:
168
+ - MIT
169
+ metadata: {}
170
+ post_install_message:
171
+ rdoc_options: []
172
+ require_paths:
173
+ - lib
174
+ required_ruby_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - ">="
182
+ - !ruby/object:Gem::Version
183
+ version: '0'
184
+ requirements: []
185
+ rubyforge_project:
186
+ rubygems_version: 2.4.6
187
+ signing_key:
188
+ specification_version: 4
189
+ summary: Painless iOS over-the-air enterprise distribution
190
+ test_files: []