longbow-fdv 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +151 -0
- data/Rakefile +9 -0
- data/bin/longbow +24 -0
- data/lib/longbow.rb +6 -0
- data/lib/longbow/colors.rb +23 -0
- data/lib/longbow/commands.rb +5 -0
- data/lib/longbow/commands/aim.rb +71 -0
- data/lib/longbow/commands/install.rb +54 -0
- data/lib/longbow/commands/shoot.rb +70 -0
- data/lib/longbow/images.rb +389 -0
- data/lib/longbow/json.rb +50 -0
- data/lib/longbow/plist.rb +64 -0
- data/lib/longbow/targets.rb +121 -0
- data/lib/longbow/utilities.rb +8 -0
- data/lib/longbow/version.rb +12 -0
- data/resources/aim.sh +31 -0
- data/resources/banner.png +0 -0
- data/resources/capture.js +84 -0
- data/resources/config-screenshots.sh +28 -0
- data/resources/ui-screen-shooter.sh +206 -0
- data/resources/unix_instruments.sh +67 -0
- metadata +181 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 417412bce1a52378508d826af49063e766f809c5
|
4
|
+
data.tar.gz: 379a1450dcfff594bc7c004f79b93afacfcf468b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 666b28e2b7c6b7bbf2f8a5f33e31758457e88cac998fba156573768f3347499669bcb301b4b715688e77e501177d9c8dbfa220c935ce2f5a0eada040d9c11f9c
|
7
|
+
data.tar.gz: 5cf73e6cd4de1b1fc11dabf24b41cfccba3e57279c670c1d12dd6433d0d90def13ed1e38919a315f675b54c9e191dcd72f70e334e43b2b9667aed25f3b2ec2cf
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Intermark Group
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
![banner](resources/banner.png)
|
2
|
+
|
3
|
+
**Problem**
|
4
|
+
|
5
|
+
One codebase. Multiple App Store submission targets with different icons, launch images, info.plist keys, screenshots, etc.
|
6
|
+
|
7
|
+
**Solution**
|
8
|
+
|
9
|
+
```
|
10
|
+
$ longbow install
|
11
|
+
$ longbow shoot
|
12
|
+
$ longbow aim
|
13
|
+
```
|
14
|
+
|
15
|
+
**About**
|
16
|
+
|
17
|
+
Longbow is a command-line run ruby gem that duplicates the main target in your `.xcworkspace` or `.xcodeproj` file, then reads from a JSON file to fill out the rest of your new target. It looks for certain keys and does things like taking an icon image and resizing it for the various icons you'll need, and adding keys to the info.plist file for that target. The goal was to be practically autonomous in creating new targets and apps.
|
18
|
+
|
19
|
+
Additionally, it can create screenshots for each target app store submission. You write a simple UIAutomation script (it's just JavaScript) and Longbow takes care of taking the screenshots for each combination of target, device, and language.
|
20
|
+
|
21
|
+
**Requirements**
|
22
|
+
|
23
|
+
Longbow requires Xcode 5+, and your app must use the new .xcassets paradigm for icons, launch screens, etc.
|
24
|
+
|
25
|
+
## Table of Contents
|
26
|
+
|
27
|
+
* [Installation](#installation)
|
28
|
+
* [Set Up](#set-up)
|
29
|
+
* [Formatting longbow.json](#formatting-longbow-json)
|
30
|
+
* [Create a Target](#create-a-target)
|
31
|
+
* [Global Options](#global-options)
|
32
|
+
* [The Future](#the-future)
|
33
|
+
* [Contributing](#contributing)
|
34
|
+
|
35
|
+
## Installation
|
36
|
+
|
37
|
+
Longbow is officially hosted on [RubyGems](http://rubygems.org/gems/longbow), so installation is a breeze:
|
38
|
+
|
39
|
+
$ gem install longbow
|
40
|
+
|
41
|
+
## Set Up
|
42
|
+
|
43
|
+
Run `longbow install` in the directory where your `.xcworkspace` or `.xcodeproj` file lives. This will create a file, `longbow.json`, where they will be used to build out from here. You are almost ready to start creating new targets
|
44
|
+
|
45
|
+
## Formatting longbow.json
|
46
|
+
|
47
|
+
Here's a basic gist of how to format your `longbow.json` file:
|
48
|
+
|
49
|
+
```json
|
50
|
+
{
|
51
|
+
"targets":[
|
52
|
+
{
|
53
|
+
"name":"TargetName",
|
54
|
+
"icon_url":"https://somewhere.net/img.png",
|
55
|
+
"launch_phone_p_url":"https://somewhere.net/img2.png",
|
56
|
+
"info_plist": {
|
57
|
+
"CFBundleIdentifier":"com.company.target1",
|
58
|
+
"ProprietaryKey":"Value"
|
59
|
+
}
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"name":"TargetName2",
|
63
|
+
"icon_path":"/relative/path/to/file.png",
|
64
|
+
"launch_phone_p_path":"/relative/path/to/file2.png",
|
65
|
+
"info_plist": {
|
66
|
+
"CFBundleIdentifier":"com.company.target2",
|
67
|
+
"ProprietaryKey":"Value2"
|
68
|
+
}
|
69
|
+
}
|
70
|
+
],
|
71
|
+
"global_info_keys":{
|
72
|
+
"somekey":"somevalue"
|
73
|
+
},
|
74
|
+
"devices":["iPhone","iPad"]
|
75
|
+
}
|
76
|
+
```
|
77
|
+
|
78
|
+
In the top-level of the JSON file, we have 3 key/value pairs:
|
79
|
+
|
80
|
+
* `targets`
|
81
|
+
* `devices`
|
82
|
+
* `global_info_keys`
|
83
|
+
|
84
|
+
The `targets` section contains nested key/value pairs for each specific target. Devices holds an array of "iPhone" and/or "iPad". "global_info_keys" contains key/value pairs that you'd like to add to the info.plist file for all targets in this JSON file. Each target can contain the following keys:
|
85
|
+
|
86
|
+
* `icon_url` or `icon_path`
|
87
|
+
* `launch_phone_p_url` or `launch_phone_p_path`
|
88
|
+
* `launch_phone_l_url` or `launch_phone_l_path`
|
89
|
+
* `launch_tablet_p_url` or `launch_tablet_p_path`
|
90
|
+
* `launch_tablet_l_url` or `launch_tablet_l_path`
|
91
|
+
* `info_plist`
|
92
|
+
* `name`
|
93
|
+
|
94
|
+
The `icon_url` and `icon_path` key corresponds to the location of the icon image. It will be downloaded from the web if necessary, then resized depending on your device setting and added to the Images.xcassets file for that target. The same goes for the launch image keys. The p and l parts correspond to portrait and landscape orientation. The `info_plist` key corresponds to another set of key/value pairs that will be added or updated in the info.plist file specifically for this target.
|
95
|
+
|
96
|
+
**Note:** `info_plist` takes precedence over `global_info_keys` for two of the same keys in both places.
|
97
|
+
|
98
|
+
## Creating/Updating a Target
|
99
|
+
|
100
|
+
Now that you're set up - it's time to add a target. Make sure that you have updated your `longbow.json` file with the correct information for your target, and then run the following command inside the project directory.
|
101
|
+
|
102
|
+
`longbow shoot -n NameOfTarget`
|
103
|
+
|
104
|
+
What this does is goes to your `longbow.json` file and looks for the correct target dictionary, and tries to create a new Target in your app. It then handles the various icons/info_plist additions specifically for this target. If your target already exists, it will just update the icon images and plist settings.
|
105
|
+
|
106
|
+
If you leave off the `-n` option, it will run for all targets in the `longbow.json` file.
|
107
|
+
|
108
|
+
**Other Options**
|
109
|
+
|
110
|
+
* `-d, --directory` - if not in the current directory, specify a new path
|
111
|
+
* `-u, --url` - the url of a longbow formatted JSON file
|
112
|
+
* `-i, --images` - set this flag to not recreate images in the longbow file
|
113
|
+
|
114
|
+
`longbow shoot -n NameOfTarget -d ~/Path/To/App -u http://someurl.com/longbow.json`
|
115
|
+
|
116
|
+
## Global Options
|
117
|
+
|
118
|
+
`--dontlog` will not log the status/operations to the console.
|
119
|
+
|
120
|
+
`--help` will fill you in on what you need to do for an action.
|
121
|
+
|
122
|
+
## Taking Screenshots
|
123
|
+
|
124
|
+
So you've created all your targets and finished the first version of the app - now you need the screen shots to submit it to the App Store.
|
125
|
+
|
126
|
+
First you'll need to write a single UIAutomation script to take the screenshots. You can see [Apple's Documentation](https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/UIAutomationRef/_index.html) for more information on writing the script. The part we're primarily concerned with is the captureLocalizedScreenshot() method provided by Longbow. This method will take the screenshot with a consistent naming scheme and place it in a folder for each target.
|
127
|
+
|
128
|
+
`captureLocalizedScreenshot("homeScreen");` will create ~/Desktop/screenshots/TargetName/en-US/iOS-4-in\_\_\_portrait\_\_\_homeScreen.png
|
129
|
+
|
130
|
+
Once you've created your automation script, you can run it by calling `longbow aim`. This command will generate a variation of your UIAutomation script for each target, then handle running it for each target. Grab a drink, depending on your script and your number of targets, this may take a while.
|
131
|
+
|
132
|
+
**Options**
|
133
|
+
|
134
|
+
Similar to the `shoot` command, there are flags you can use with this feature.
|
135
|
+
|
136
|
+
* `-n` - name of the target to capture
|
137
|
+
* `-d` - directory the project lives in
|
138
|
+
* `-u` - url of the longbow.json file
|
139
|
+
|
140
|
+
## The Future
|
141
|
+
|
142
|
+
* Unit Tests
|
143
|
+
* App Store deployment of Targets
|
144
|
+
|
145
|
+
## Contributing
|
146
|
+
|
147
|
+
1. Fork it
|
148
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
149
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
150
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
151
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/longbow
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dotenv'
|
4
|
+
Dotenv.load
|
5
|
+
|
6
|
+
require 'commander/import'
|
7
|
+
|
8
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
9
|
+
require 'longbow'
|
10
|
+
|
11
|
+
HighLine.track_eof = false # Fix for built-in Ruby
|
12
|
+
|
13
|
+
program :version, Longbow::VERSION
|
14
|
+
program :description, 'One codebase. Multiple App Store submission targets with different icons, launch images, info.plist keys, etc.'
|
15
|
+
|
16
|
+
program :help, 'Author', 'Benjamin Gordon (@bennyguitar) for Intermark Group <interactive@intermarkgroup.com>'
|
17
|
+
program :help, 'Website', 'https://github.com/intermark'
|
18
|
+
program :help_formatter, :compact
|
19
|
+
|
20
|
+
global_option('--dontlog') { $nolog = true }
|
21
|
+
|
22
|
+
default_command :help
|
23
|
+
|
24
|
+
require 'longbow/commands'
|
data/lib/longbow.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Longbow
|
2
|
+
# Main Colorize Functions
|
3
|
+
def self.colorize(text, color_code)
|
4
|
+
puts "\e[#{color_code}m#{text}\e[0m"
|
5
|
+
end
|
6
|
+
|
7
|
+
# Specific Colors
|
8
|
+
def self.red(text)
|
9
|
+
colorize(text, 31)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.green(text)
|
13
|
+
colorize(text, 32)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.blue(text)
|
17
|
+
colorize(text, 36)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.purple(text)
|
21
|
+
colorize(text, 35)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'longbow/colors'
|
3
|
+
require 'longbow/targets'
|
4
|
+
require 'longbow/images'
|
5
|
+
require 'longbow/json'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
command :aim do |c|
|
9
|
+
c.syntax = 'longbow aim'
|
10
|
+
c.syntax = 'Takes screenshots for each target in your workspace or project based on a UIAutomation script.'
|
11
|
+
c.description = ''
|
12
|
+
c.option '-s', '--script SCRIPT', 'Script used to get the app into the proper state for each screenshot'
|
13
|
+
c.option '-d', '--directory DIRECTORY', 'Path where the .xcodeproj or .xcworkspace file && the longbow.json file live.'
|
14
|
+
c.option '-u', '--url URL', 'URL of a longbow formatted JSON file.'
|
15
|
+
c.option '-n', '--name NAME', 'Name of the target to get a screenshot for.'
|
16
|
+
c.option '-v', '--verbose', 'Output all logs from UIAutomation/xcodebuild'
|
17
|
+
|
18
|
+
c.action do |args, options|
|
19
|
+
# Check for newer version
|
20
|
+
Longbow::check_for_newer_version unless $nolog
|
21
|
+
|
22
|
+
# Set Up
|
23
|
+
@script = options.script ? options.script : nil
|
24
|
+
@directory = options.directory ? options.directory : Dir.pwd
|
25
|
+
@url = options.url ? options.url : nil
|
26
|
+
@target_name = options.name
|
27
|
+
@targets = []
|
28
|
+
|
29
|
+
# Create JSON object
|
30
|
+
if @url
|
31
|
+
obj = Longbow::json_object_from_url @url
|
32
|
+
else
|
33
|
+
obj = Longbow::json_object_from_directory @directory
|
34
|
+
end
|
35
|
+
|
36
|
+
# Break if Bad
|
37
|
+
unless obj || Longbow::lint_json_object(obj)
|
38
|
+
Longbow::red "\n Invalid JSON. Please lint the file, and try again.\n"
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
# Check for Target Name
|
43
|
+
if @target_name
|
44
|
+
obj['targets'].each do |t|
|
45
|
+
@targets << t if t['name'] == @target_name
|
46
|
+
end
|
47
|
+
|
48
|
+
if @targets.length == 0
|
49
|
+
Longbow::red "\n Couldn't find a target named #{@target_name} in the longbow.json file.\n"
|
50
|
+
next
|
51
|
+
end
|
52
|
+
else
|
53
|
+
@targets = obj['targets']
|
54
|
+
end
|
55
|
+
|
56
|
+
resources_path = File.dirname(__FILE__) + '/../../../resources'
|
57
|
+
|
58
|
+
FileUtils.cp "#{resources_path}/capture.js", "capture.js"
|
59
|
+
FileUtils.cp "#{resources_path}/config-screenshots.sh", "config-screenshots.sh"
|
60
|
+
FileUtils.cp "#{resources_path}/ui-screen-shooter.sh", "ui-screen-shooter.sh"
|
61
|
+
FileUtils.cp "#{resources_path}/unix_instruments.sh", "unix_instruments.sh"
|
62
|
+
@target_names = []
|
63
|
+
@targets.each do |t|
|
64
|
+
@target_names << t['name']
|
65
|
+
end
|
66
|
+
target_string = @target_names.join(',')
|
67
|
+
Longbow::blue " Beginning screenshots..."
|
68
|
+
exec "#{resources_path}/aim.sh #{target_string} verbose" if options.verbose
|
69
|
+
exec "#{resources_path}/aim.sh #{target_string}" if !options.verbose
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
$:.push File.expand_path('../../', __FILE__)
|
2
|
+
require 'fileutils'
|
3
|
+
require 'longbow'
|
4
|
+
|
5
|
+
command :install do |c|
|
6
|
+
c.syntax = 'longbow install [options]'
|
7
|
+
c.summary = 'Creates the required files in your directory.'
|
8
|
+
c.description = ''
|
9
|
+
c.option '-d', '--directory DIRECTORY', 'Path where the .xcproj or .xcworkspace file && the longbow.json file live.'
|
10
|
+
|
11
|
+
c.action do |args, options|
|
12
|
+
# Check for newer version
|
13
|
+
Longbow::check_for_newer_version unless $nolog
|
14
|
+
|
15
|
+
# Set Up
|
16
|
+
@directory = options.directory ? options.directory : Dir.pwd
|
17
|
+
@json_path = @directory + '/longbow.json'
|
18
|
+
|
19
|
+
# Install
|
20
|
+
if File.exist?(@json_path)
|
21
|
+
Longbow::red ' longbow.json already exists at ' + @json_path
|
22
|
+
else
|
23
|
+
File.open(@json_path, 'w') do |f|
|
24
|
+
f.write('{
|
25
|
+
"targets":[
|
26
|
+
{
|
27
|
+
"name":"TargetName",
|
28
|
+
"icon_url":"https://somewhere.net/img.png",
|
29
|
+
"launch_phone_p_url":"https://somewhere.net/img2.png",
|
30
|
+
"info_plist": {
|
31
|
+
"CFBundleIdentifier":"com.company.target1",
|
32
|
+
"ProprietaryKey":"Value"
|
33
|
+
}
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"name":"TargetName2",
|
37
|
+
"icon_path":"/relative/path/to/file.png",
|
38
|
+
"launch_phone_p_path":"/relative/path/to/file2.png",
|
39
|
+
"info_plist": {
|
40
|
+
"CFBundleIdentifier":"com.company.target2",
|
41
|
+
"ProprietaryKey":"Value2"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
],
|
45
|
+
"global_info_keys":{
|
46
|
+
"somekey":"somevalue"
|
47
|
+
},
|
48
|
+
"devices":["iPhone","iPad"]
|
49
|
+
}')
|
50
|
+
end
|
51
|
+
Longbow::green ' longbow.json created' unless $nolog
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
$:.push File.expand_path('../../', __FILE__)
|
2
|
+
require 'fileutils'
|
3
|
+
require 'longbow/colors'
|
4
|
+
require 'longbow/targets'
|
5
|
+
require 'longbow/images'
|
6
|
+
require 'longbow/json'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
command :shoot do |c|
|
10
|
+
c.syntax = 'longbow shoot [options]'
|
11
|
+
c.summary = 'Creates/updates a target or all targets in your workspace or project.'
|
12
|
+
c.description = ''
|
13
|
+
c.option '-n', '--name NAME', 'Target name from the corresponding longbow.json file.'
|
14
|
+
c.option '-d', '--directory DIRECTORY', 'Path where the .xcodeproj or .xcworkspace file && the longbow.json file live.'
|
15
|
+
c.option '-u', '--url URL', 'URL of a longbow formatted JSON file.'
|
16
|
+
c.option '-i', '--images', 'Set this flag to not recreate images in the longbow file.'
|
17
|
+
|
18
|
+
c.action do |args, options|
|
19
|
+
# Check for newer version
|
20
|
+
Longbow::check_for_newer_version unless $nolog
|
21
|
+
|
22
|
+
# Set Up
|
23
|
+
@target_name = options.name ? options.name : nil
|
24
|
+
@directory = options.directory ? options.directory : Dir.pwd
|
25
|
+
|
26
|
+
puts 'Directory'
|
27
|
+
puts @directory
|
28
|
+
|
29
|
+
@noimages = options.images ? true : false
|
30
|
+
@url = options.url ? options.url : nil
|
31
|
+
@targets = []
|
32
|
+
|
33
|
+
# Create JSON object
|
34
|
+
if @url
|
35
|
+
obj = Longbow::json_object_from_url @url
|
36
|
+
else
|
37
|
+
obj = Longbow::json_object_from_directory @directory
|
38
|
+
end
|
39
|
+
|
40
|
+
# Break if Bad
|
41
|
+
unless obj || Longbow::lint_json_object(obj)
|
42
|
+
Longbow::red "\n Invalid JSON. Please lint the file, and try again.\n"
|
43
|
+
next
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Check for Target Name
|
48
|
+
if @target_name
|
49
|
+
obj['targets'].each do |t|
|
50
|
+
@targets << t if t['name'] == @target_name
|
51
|
+
end
|
52
|
+
|
53
|
+
if @targets.length == 0
|
54
|
+
Longbow::red "\n Couldn't find a target named #{@target_name} in the longbow.json file.\n"
|
55
|
+
next
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@targets = obj['targets']
|
59
|
+
end
|
60
|
+
|
61
|
+
# Begin
|
62
|
+
@targets.each do |t|
|
63
|
+
icon = t['icon_url'] || t['icon_path']
|
64
|
+
launch = t['launch_phone_p_url'] || t['launch_phone_p_path'] || t['launch_phone_l_url'] || t['launch_phone_l_path'] || t['launch_tablet_p_url'] || t['launch_tablet_p_path'] || t['launch_tablet_l_url'] || t['launch_tablet_l_path']
|
65
|
+
Longbow::update_target @directory, t['name'], obj['global_info_keys'], t['info_plist'], icon, launch
|
66
|
+
# Longbow::create_images(@directory, t, obj) unless @noimages
|
67
|
+
Longbow::green " Finished: #{t['name']}\n" unless $nolog
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|