flick 0.1.0 → 0.2.0
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/README.md +39 -30
- data/bin/flick +21 -5
- data/flick.gemspec +4 -1
- data/lib/flick.rb +6 -1
- data/lib/flick/android.rb +63 -32
- data/lib/flick/checker.rb +30 -4
- data/lib/flick/ios.rb +36 -13
- data/lib/flick/log.rb +17 -7
- data/lib/flick/manager.rb +41 -0
- data/lib/flick/screenshot.rb +10 -6
- data/lib/flick/simple_daemon.rb +18 -12
- data/lib/flick/system.rb +36 -16
- data/lib/flick/version.rb +1 -1
- data/lib/flick/video.rb +37 -42
- metadata +57 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb64107c4d21b8fc509321fdc0d98763e3e376e6
|
4
|
+
data.tar.gz: 154aa4c74efa4fead2f6cdd5880c7b71602607ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07dba93a03a97b5a725bc98afca7e3cda8c66138aab7ae1f15efaa6f3caf4a43a01599344117130f04f54391ef6c40629178b66e714c5693e0d1dacd7f026c43
|
7
|
+
data.tar.gz: 7e400657a20828488546d0229b251fe3bbe7a125c25aee55eb23aba1cc41fdc275b0d2aa6bd4c76c1c04295194e535fdd2bddab91a18486db83214081abd991e
|
data/README.md
CHANGED
@@ -14,6 +14,7 @@ Features
|
|
14
14
|
* Falls back to screenshot recording if video record is not available.
|
15
15
|
* Video record android emulators and **real** iOS devices.
|
16
16
|
* Takes a screenshot every 0.5 seconds (default), then combines the screenshots into a single mp4 or gif.
|
17
|
+
* Android pulls only unique (default) screenshots from devices/emulators. e.g. A 1 minute test run might convert to only 30 seconds of video based on unique images. You can change this by passing `-q false` to pull all images instead.
|
17
18
|
* iOS example [here](https://www.dropbox.com/s/4pjhhmnsx9gj5pi/ios-flick-example.mp4?dl=0)
|
18
19
|
* Android Emulator example [here](https://www.dropbox.com/s/gwunrvgzxkny13z/android-flick-example.mp4?dl=0)
|
19
20
|
* Flick auto selects device when only one device is connected, per platform.
|
@@ -28,17 +29,24 @@ So I created Flick to work for my needs, and included a couple other tools I use
|
|
28
29
|
|
29
30
|
If you're looking for high-quality video, then this wouldn't be the tool for you. Take a look at this great tool [androidtool-mac](https://github.com/mortenjust/androidtool-mac) instead.
|
30
31
|
|
31
|
-
Prerequisites
|
32
|
+
Prerequisites
|
32
33
|
-------------
|
33
34
|
#### System Tools
|
34
35
|
* Install ffmpeg. [OSX](https://trac.ffmpeg.org/wiki/CompilationGuide/MacOSX)
|
35
36
|
* ```$ brew install ffmpeg```
|
37
|
+
* Install ffmpeg. [Windows](https://ffmpeg.zeranoe.com/builds/)
|
38
|
+
* Download either the 32-bit or 64-bit static versions.
|
39
|
+
* Extract the zip file and move the ffmpeg folder somewhere else.
|
40
|
+
* Add the ffmpeg bin location to your PATH user variables. e.g. C:\ffmpeg\bin
|
36
41
|
* Install mp4box. [OSX](http://hunterford.me/compiling-mp4box-on-mac-os-x/)
|
37
42
|
* ```$ brew install mp4box```
|
43
|
+
* Install mp4box. [Windows](http://www.videohelp.com/software/MP4Box)
|
44
|
+
* Run the gpac-0.6.2-DEV-rev634-gd2332cb-master-x(64 or 32 bit).exe
|
45
|
+
* Select to install only the MP4Box component.
|
38
46
|
|
39
47
|
#### Android
|
40
48
|
* Install [SDK Tools](http://developer.android.com/sdk/installing/index.html?pkg=tools).
|
41
|
-
* SDK tools are added to your $PATH. [OSX](http://stackoverflow.com/questions/5526470/trying-to-add-adb-to-path-variable-osx)
|
49
|
+
* SDK tools are added to your $PATH. [OSX](http://stackoverflow.com/questions/5526470/trying-to-add-adb-to-path-variable-osx)
|
42
50
|
* Enable [USB Debugging](https://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htm) on your device(s).
|
43
51
|
* Emulator or Devices have approximately 1GB of [sdcard space](http://developer.android.com/tools/help/mksdcard.html).
|
44
52
|
|
@@ -60,54 +68,55 @@ Usage:
|
|
60
68
|
$ flick --help
|
61
69
|
|
62
70
|
DESCRIPTION:
|
63
|
-
|
71
|
+
|
64
72
|
A CLI to capture screenshots, video, logs, and device info for Android (Devices & Emulators) and iOS (Devices).
|
65
|
-
|
73
|
+
|
66
74
|
COMMANDS:
|
67
|
-
|
68
|
-
help Display global or [command] help documentation
|
69
|
-
info Get device information
|
70
|
-
log Get device log output
|
71
|
-
screenshot Take a screenshot
|
72
|
-
video Record video
|
73
|
-
|
75
|
+
|
76
|
+
help Display global or [command] help documentation
|
77
|
+
info Get device information
|
78
|
+
log Get device log output
|
79
|
+
screenshot Take a screenshot
|
80
|
+
video Record video
|
81
|
+
|
74
82
|
GLOBAL OPTIONS:
|
75
|
-
|
76
|
-
-h, --help
|
83
|
+
|
84
|
+
-h, --help
|
77
85
|
Display help documentation
|
78
|
-
|
79
|
-
-v, --version
|
86
|
+
|
87
|
+
-v, --version
|
80
88
|
Display version information
|
81
|
-
|
82
|
-
-t, --trace
|
89
|
+
|
90
|
+
-t, --trace
|
83
91
|
Display backtrace when an error occurs
|
84
92
|
|
85
|
-
* See usage examples in:
|
86
|
-
|
87
93
|
`$ flick info --help`
|
88
|
-
|
94
|
+
|
89
95
|
$ flick info -p (ios or android)
|
90
96
|
$ flick info -p (ios or android) -s true -o $HOME
|
91
|
-
|
92
|
-
|
97
|
+
|
98
|
+
|
93
99
|
`$ flick log --help`
|
94
|
-
|
100
|
+
|
95
101
|
$ flick log -a start -p (ios or android) -o $HOME -n iosLog
|
96
102
|
$ flick log -a stop -p (ios or android)
|
97
103
|
|
98
104
|
`$ flick screenshot --help`
|
99
|
-
|
100
|
-
$ flick screenshot -p (ios or android)
|
101
|
-
|
105
|
+
|
106
|
+
$ flick screenshot -p (ios or android) -o $HOME -n myImage
|
107
|
+
|
102
108
|
`$ flick video --help`
|
103
|
-
|
109
|
+
|
104
110
|
$ flick video -a start -p (ios or android)
|
105
111
|
$ flick video -a stop -p (ios or android) -o /output -n myVideo -f gif
|
106
112
|
$ flick video -a start -p android -u emulator-5554 -c 1000
|
107
113
|
$ flick video -a stop -p android -u emulator-5554
|
108
114
|
|
109
|
-
|
110
|
-
|
115
|
+
`$ flick manager --help`
|
116
|
+
$ flick manager -a install -p (ios or android) -f ~/myApp/my-awesome-app.apk or .app
|
117
|
+
$ flick maanger -a uninstall -p (ios or android) -n com.package.name
|
118
|
+
|
119
|
+
##Demo
|
111
120
|
<img src="https://www.dropbox.com/s/9be37gc1c2dlxa6/flick-demo.gif?raw=1" width="600">
|
112
121
|
|
113
122
|
## Contributing
|
@@ -119,7 +128,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/isonic
|
|
119
128
|
* Setup Flick android for cross platform os's (windows & linux)
|
120
129
|
* Add screenshot capture for iOS Simulators.
|
121
130
|
* Multithread the screenshot and pull process.
|
122
|
-
* Look into capturing video
|
131
|
+
* Look into capturing video for iOS similar to [this](https://github.com/mortenjust/androidtool-mac/blob/9347cd9aeca9e7370e323d12f862bc5d8beacc25/AndroidTool/IOSDeviceHelper.swift#L56)
|
123
132
|
|
124
133
|
## License
|
125
134
|
|
data/bin/flick
CHANGED
@@ -28,7 +28,7 @@ command :video do |c|
|
|
28
28
|
:unique => true, #defaults to pulling only unique screenshots. Speeds up pulling process from device.
|
29
29
|
:format => "mp4",
|
30
30
|
:outdir => Dir.pwd #defaults to save in current directory.
|
31
|
-
|
31
|
+
|
32
32
|
Video.new(options.default).run
|
33
33
|
end
|
34
34
|
end
|
@@ -45,11 +45,11 @@ command :screenshot do |c|
|
|
45
45
|
c.action do |args, options|
|
46
46
|
options.default \
|
47
47
|
:outdir => Dir.pwd #defaults to save in current directory.
|
48
|
-
|
48
|
+
|
49
49
|
Screenshot.new(options.default).screenshot
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
command :log do |c|
|
54
54
|
c.syntax = 'flick log [options]'
|
55
55
|
c.summary = 'Get device log output'
|
@@ -63,7 +63,7 @@ command :log do |c|
|
|
63
63
|
c.action do |args, options|
|
64
64
|
options.default \
|
65
65
|
:outdir => Dir.pwd #defaults to save in current directory.
|
66
|
-
|
66
|
+
|
67
67
|
Log.new(options.default).run
|
68
68
|
end
|
69
69
|
end
|
@@ -81,7 +81,23 @@ command :info do |c|
|
|
81
81
|
options.default \
|
82
82
|
:save => false,
|
83
83
|
:outdir => Dir.pwd #defaults to save in current directory.
|
84
|
-
|
84
|
+
|
85
85
|
Info.new(options.default).info
|
86
86
|
end
|
87
|
+
end
|
88
|
+
|
89
|
+
command :manager do |c|
|
90
|
+
c.syntax = 'flick manager [options]'
|
91
|
+
c.summary = 'Manage apps on devices'
|
92
|
+
c.description = c.summary
|
93
|
+
c.example 'description', "flick manager -a install -p android -f ~/my-awesome-app.apk\n flick manager -a uninstall -p ios -n com.viber"
|
94
|
+
c.option '-a', '--action ACTION', String, 'Set action: install or uninstall'
|
95
|
+
c.option '-p', '--platform PLATFORM', String, 'Set platform: android or ios'
|
96
|
+
c.option '-u', '--udid UDID', String, 'Set device UDID.'
|
97
|
+
c.option '-f', '--file FILE', String, 'Set the apk or app file location path.'
|
98
|
+
c.option '-n', '--name NAME', String, 'Set the package name.'
|
99
|
+
c.action do |args, options|
|
100
|
+
|
101
|
+
Manager.new(options.default).run
|
102
|
+
end
|
87
103
|
end
|
data/flick.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.bindir = "bin"
|
25
25
|
spec.executables = ["flick"]
|
26
26
|
spec.require_paths = ["lib"]
|
27
|
-
|
27
|
+
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.10"
|
29
29
|
spec.add_development_dependency "rake", "~> 10.0"
|
30
30
|
spec.add_development_dependency "rspec", '~> 3.4', '>= 3.4.0'
|
@@ -34,4 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_dependency "json", '~> 1.8', '>= 1.8.3'
|
35
35
|
spec.add_dependency "wannabe_bool", "~> 0.5.0"
|
36
36
|
spec.add_dependency "awesome_print", '~> 1.6', '>= 1.6.1'
|
37
|
+
spec.add_dependency "os", "~> 0.9.6"
|
38
|
+
spec.add_dependency "sys-proctable", '~> 1.1', '>= 1.1.1'
|
39
|
+
spec.add_dependency "apktools", '~> 0.7.1', '>= 0.7.1'
|
37
40
|
end
|
data/lib/flick.rb
CHANGED
@@ -3,6 +3,10 @@ require 'json'
|
|
3
3
|
require 'parallel'
|
4
4
|
require 'wannabe_bool'
|
5
5
|
require 'awesome_print'
|
6
|
+
require 'os'
|
7
|
+
require 'tempfile'
|
8
|
+
require 'sys/proctable'
|
9
|
+
require 'apktools/apkxml'
|
6
10
|
|
7
11
|
require "flick/version"
|
8
12
|
require_relative "./flick/android"
|
@@ -13,4 +17,5 @@ require_relative "./flick/log"
|
|
13
17
|
require_relative "./flick/screenshot"
|
14
18
|
require_relative "./flick/simple_daemon"
|
15
19
|
require_relative "./flick/system"
|
16
|
-
require_relative "./flick/video"
|
20
|
+
require_relative "./flick/video"
|
21
|
+
require_relative "./flick/manager"
|
data/lib/flick/android.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Flick
|
2
2
|
class Android
|
3
3
|
attr_accessor :flick_dir, :dir_name, :udid, :name, :outdir, :unique, :limit, :specs
|
4
|
-
|
4
|
+
|
5
5
|
def initialize options
|
6
6
|
Flick::Checker.system_dependency "adb"
|
7
7
|
self.flick_dir = "#{Dir.home}/.flick"
|
@@ -14,43 +14,43 @@ module Flick
|
|
14
14
|
self.specs = options.fetch(:specs, false)
|
15
15
|
create_flick_dirs
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def create_flick_dirs
|
19
19
|
Flick::System.setup_system_dir flick_dir
|
20
|
-
%x(adb -s #{udid} shell 'mkdir #{dir_name}'
|
20
|
+
%x(adb -s #{udid} shell 'mkdir #{dir_name}')
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def clear_files
|
24
|
-
%x(adb -s #{udid} shell rm '#{dir_name}/*' >> /dev/null 2>&1)
|
25
24
|
Flick::System.clean_system_dir flick_dir, udid
|
25
|
+
%x(adb -s #{udid} shell rm '#{dir_name}/*')
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def devices
|
29
29
|
(`adb devices`).scan(/\n(.*)\t/).flatten
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def devices_connected?
|
33
|
-
|
33
|
+
devices.any?
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def check_for_devices
|
37
37
|
unless devices_connected?
|
38
|
-
puts "\nNo Devices Connected or Authorized!!!\nMake sure at least one device (emulator/simulator) is
|
38
|
+
puts "\nNo Devices Connected or Authorized!!!\nMake sure at least one device (emulator/simulator) is connected!\n".red
|
39
39
|
abort
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def get_device_udid opts_hash
|
44
44
|
devices_connected?
|
45
45
|
return unless opts_hash[:udid].nil?
|
46
46
|
if devices.size == 1
|
47
|
-
devices
|
47
|
+
devices.first
|
48
48
|
else
|
49
49
|
puts "\nMultiple android devices '#{devices}' found.\nSpecify a single UDID. e.g. -u #{devices.sample}\n".red
|
50
50
|
abort unless specs
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def info
|
55
55
|
specs = { os: "ro.build.version.release", manufacturer: "ro.product.manufacturer", model: "ro.product.model", sdk: "ro.build.version.sdk" }
|
56
56
|
hash = { udid: udid }
|
@@ -61,54 +61,85 @@ module Flick
|
|
61
61
|
hash
|
62
62
|
end
|
63
63
|
|
64
|
+
def install app_path
|
65
|
+
%x(adb -s #{udid} install -r #{app_path})
|
66
|
+
end
|
67
|
+
|
68
|
+
def uninstall package
|
69
|
+
if app_installed? package
|
70
|
+
%x(adb -s #{udid} shell pm uninstall #{package})
|
71
|
+
else
|
72
|
+
puts packages
|
73
|
+
puts "\n#{package} was not found on device #{udid}! Please choose one from above. e.g. #{packages.sample}\n".red
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def app_version app_path
|
78
|
+
manifest(app_path).find {|x| x.name == "versionName" }["value"]
|
79
|
+
end
|
80
|
+
|
81
|
+
def package_name app_path
|
82
|
+
manifest(app_path).find {|x| x.name == "package" }["value"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def manifest app_path
|
86
|
+
data = ApkXml.new app_path
|
87
|
+
data.parse_xml("AndroidManifest.xml", false, true)
|
88
|
+
data.xml_elements[0].attributes
|
89
|
+
end
|
90
|
+
|
91
|
+
def app_installed? package
|
92
|
+
packages.include? "package:#{package}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def packages
|
96
|
+
%x(adb -s #{udid} shell pm list packages).split
|
97
|
+
end
|
98
|
+
|
64
99
|
def os_version
|
65
|
-
|
100
|
+
%x(adb -s #{udid} shell getprop "ro.build.version.release").strip.to_f
|
66
101
|
end
|
67
|
-
|
102
|
+
|
68
103
|
def screenshot name
|
69
104
|
%x(adb -s #{udid} shell screencap #{dir_name}/#{name}.png)
|
70
105
|
end
|
71
|
-
|
106
|
+
|
72
107
|
def log name
|
73
108
|
%x(adb -s #{udid} logcat -v long > #{outdir}/#{name}.log)
|
74
109
|
end
|
75
|
-
|
110
|
+
|
76
111
|
def recordable?
|
77
|
-
(
|
112
|
+
%x(adb -s #{udid} shell "ls /system/bin/screenrecord").strip == "/system/bin/screenrecord"
|
78
113
|
end
|
79
|
-
|
114
|
+
|
80
115
|
def screenrecord name
|
81
116
|
%x(adb -s #{udid} shell screenrecord --time-limit #{limit} --size 720x1280 #{dir_name}/#{name}.mp4)
|
82
117
|
end
|
83
|
-
|
118
|
+
|
84
119
|
def pull_file file, dir
|
85
|
-
%x(adb -s #{udid} pull #{file} #{dir}
|
120
|
+
%x(adb -s #{udid} pull #{file} #{dir})
|
86
121
|
end
|
87
|
-
|
88
|
-
def unique_files
|
122
|
+
|
123
|
+
def unique_files type
|
89
124
|
if os_version < 6.0
|
90
125
|
command = "md5"
|
91
126
|
else
|
92
127
|
command = "md5sum"
|
93
128
|
end
|
94
|
-
files =
|
129
|
+
files = %x(adb -s #{udid} shell "#{command} #{dir_name}/#{type}-#{udid}*")
|
95
130
|
hash = files.split("\r\n").map { |file| { md5: file.match(/(.*) /)[1].strip, file: file.match(/ (.*)/)[1].strip } }
|
96
131
|
hash.uniq! { |e| e[:md5] }
|
97
132
|
hash.map { |file| file[:file] }
|
98
133
|
end
|
99
|
-
|
100
|
-
def pull_files
|
134
|
+
|
135
|
+
def pull_files type
|
101
136
|
if unique
|
102
|
-
files = unique_files
|
137
|
+
files = unique_files type
|
103
138
|
else
|
104
|
-
files = (
|
139
|
+
files = %x(adb -s #{udid} shell "ls #{dir_name}/#{type}-#{udid}*").split("\r\n")
|
105
140
|
end
|
106
141
|
return if files.empty?
|
107
142
|
Parallel.map(files, in_threads: 10) { |file| pull_file file, flick_dir }
|
108
143
|
end
|
109
|
-
|
110
|
-
def screenshots_exist?
|
111
|
-
(`adb -s #{udid} shell "ls #{dir_name}/#{udid}-*.png | wc -l"`).to_i > 0
|
112
|
-
end
|
113
144
|
end
|
114
145
|
end
|
data/lib/flick/checker.rb
CHANGED
@@ -1,13 +1,24 @@
|
|
1
1
|
module Flick
|
2
2
|
module Checker
|
3
|
+
def self.which(cmd)
|
4
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
5
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
6
|
+
exts.each { |ext|
|
7
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
8
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
9
|
+
}
|
10
|
+
end
|
11
|
+
return nil
|
12
|
+
end
|
13
|
+
|
3
14
|
def self.system_dependency dep
|
4
|
-
program =
|
15
|
+
program = self.which dep
|
5
16
|
if program.empty?
|
6
17
|
puts "\n#{dep} was not found. Please ensure you have installed #{dep} and it's in your $PATH\n".red
|
7
18
|
abort
|
8
19
|
end
|
9
20
|
end
|
10
|
-
|
21
|
+
|
11
22
|
def self.platform platform
|
12
23
|
platforms = ["android","ios"]
|
13
24
|
unless platforms.include? platform
|
@@ -15,7 +26,7 @@ module Flick
|
|
15
26
|
abort
|
16
27
|
end
|
17
28
|
end
|
18
|
-
|
29
|
+
|
19
30
|
def self.action action
|
20
31
|
actions = ["start","stop"]
|
21
32
|
unless actions.include? action
|
@@ -23,7 +34,22 @@ module Flick
|
|
23
34
|
abort
|
24
35
|
end
|
25
36
|
end
|
26
|
-
|
37
|
+
|
38
|
+
def self.manager option
|
39
|
+
options = ["install","uninstall"]
|
40
|
+
unless options.include? option
|
41
|
+
puts "\nPlease specify a valid option #{options}. e.g. flick <job> -a #{options.sample} -p ios\n".red
|
42
|
+
abort
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.file_exists? file
|
47
|
+
unless File.exists? file
|
48
|
+
puts "\n#{file} does not exist! Please specify a valid file path.".red
|
49
|
+
abort
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
27
53
|
def self.format format
|
28
54
|
formats = ["mp4","gif"]
|
29
55
|
unless formats.include? format
|
data/lib/flick/ios.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Flick
|
2
2
|
class Ios
|
3
3
|
attr_accessor :flick_dir, :udid, :name, :outdir, :todir, :specs
|
4
|
-
|
4
|
+
|
5
5
|
def initialize options
|
6
6
|
Flick::Checker.system_dependency "idevice_id"
|
7
7
|
self.flick_dir = "#{Dir.home}/.flick"
|
@@ -12,26 +12,26 @@ module Flick
|
|
12
12
|
self.specs = options.fetch(:specs, false)
|
13
13
|
create_flick_dirs
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def create_flick_dirs
|
17
17
|
Flick::System.setup_system_dir flick_dir
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def devices
|
21
21
|
(`idevice_id -l`).split.uniq.map { |d| d }
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def devices_connected?
|
25
|
-
|
25
|
+
devices.any?
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def check_for_devices
|
29
29
|
unless devices_connected?
|
30
30
|
puts "\nNo iPhone or iPad Devices Connected!!!\nMake sure at least one REAL device is connected!\n".red
|
31
31
|
abort
|
32
|
-
end
|
32
|
+
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def get_device_udid opts_hash
|
36
36
|
check_for_devices
|
37
37
|
return unless opts_hash[:udid].nil?
|
@@ -42,7 +42,7 @@ module Flick
|
|
42
42
|
abort unless specs
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def info
|
47
47
|
specs = { os: "ProductVersion", name: "DeviceName", arc: "CPUArchitecture", type: "DeviceClass", sdk: "ProductType" }
|
48
48
|
hash = { udid: udid }
|
@@ -52,23 +52,46 @@ module Flick
|
|
52
52
|
end
|
53
53
|
hash
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def recordable?
|
57
57
|
false
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def clear_files
|
61
61
|
Flick::System.clean_system_dir flick_dir, udid
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def screenshot name
|
65
65
|
Flick::Checker.system_dependency "idevicescreenshot"
|
66
66
|
%x(idevicescreenshot -u #{udid} #{todir}/#{name}.png)
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def log name
|
70
70
|
Flick::Checker.system_dependency "idevicesyslog"
|
71
71
|
%x(idevicesyslog -u #{udid} > #{outdir}/#{name}.log)
|
72
72
|
end
|
73
|
+
|
74
|
+
def install app_path
|
75
|
+
Flick::Checker.system_dependency "ideviceinstaller"
|
76
|
+
%x(ideviceinstaller -u #{udid} -i #{app_path})
|
77
|
+
end
|
78
|
+
|
79
|
+
def uninstall package
|
80
|
+
Flick::Checker.system_dependency "ideviceinstaller"
|
81
|
+
if app_installed? package
|
82
|
+
%x(ideviceinstaller -u #{udid} -U #{package})
|
83
|
+
else
|
84
|
+
puts packages
|
85
|
+
puts "\n#{package} was not found on device #{udid}! Please choose one from above. e.g. #{packages.sample}\n".red
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def app_installed? package
|
90
|
+
packages.include? "#{package}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def packages
|
94
|
+
%x(ideviceinstaller -u #{udid} -l -o list_user).split("\n")[1..100000].map { |p| p.match(/(.*) -/)[1] }
|
95
|
+
end
|
73
96
|
end
|
74
97
|
end
|
data/lib/flick/log.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Log
|
2
|
-
|
2
|
+
|
3
3
|
attr_accessor :action, :platform, :driver, :udid
|
4
|
-
|
4
|
+
|
5
5
|
def initialize options
|
6
6
|
Flick::Checker.action options[:action]
|
7
7
|
Flick::Checker.platform options[:platform]
|
@@ -16,24 +16,34 @@ class Log
|
|
16
16
|
end
|
17
17
|
self.udid = self.driver.udid
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
def android
|
21
|
+
platform == "android"
|
22
|
+
end
|
23
|
+
|
24
|
+
def ios
|
25
|
+
platform == "ios"
|
26
|
+
end
|
27
|
+
|
20
28
|
def run
|
21
29
|
self.send(action)
|
22
30
|
end
|
23
|
-
|
31
|
+
|
24
32
|
def start
|
25
33
|
puts "Saving to #{driver.outdir}/#{driver.name}.log"
|
26
34
|
log
|
27
35
|
end
|
28
|
-
|
36
|
+
|
29
37
|
def stop
|
30
38
|
Flick::System.kill_process "log", udid
|
39
|
+
Flick::System.kill "idevicesyslog -u #{udid}" if ios
|
40
|
+
Flick::System.kill "adb -s #{udid} logcat" if android
|
31
41
|
end
|
32
|
-
|
42
|
+
|
33
43
|
def log
|
34
44
|
stop
|
35
45
|
$0 = "flick-log-#{udid}"
|
36
|
-
SimpleDaemon.daemonize!
|
46
|
+
SimpleDaemon.daemonize!
|
37
47
|
command = -> do
|
38
48
|
driver.log driver.name
|
39
49
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class Manager
|
2
|
+
|
3
|
+
attr_accessor :action, :platform, :driver, :udid, :file, :name
|
4
|
+
|
5
|
+
def initialize options
|
6
|
+
Flick::Checker.manager options[:action]
|
7
|
+
Flick::Checker.platform options[:platform]
|
8
|
+
self.action = options[:action]
|
9
|
+
self.platform = options[:platform]
|
10
|
+
case platform
|
11
|
+
when "ios"
|
12
|
+
self.driver = Flick::Ios.new options
|
13
|
+
when "android"
|
14
|
+
self.driver = Flick::Android.new options
|
15
|
+
end
|
16
|
+
self.udid = self.driver.udid
|
17
|
+
self.file = options[:file]
|
18
|
+
self.name = options[:name]
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
self.send(action)
|
23
|
+
end
|
24
|
+
|
25
|
+
def install
|
26
|
+
if file.nil?
|
27
|
+
puts "Specify a file path. e.g. -f #{Dir.home}/myApp/amazing-app.apk or .app".red; abort
|
28
|
+
else
|
29
|
+
Flick::Checker.file_exists? file
|
30
|
+
driver.install file
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def uninstall
|
35
|
+
if name.nil?
|
36
|
+
puts "Specify a Package Name or Bundle ID. e.g. -n ".red; abort
|
37
|
+
else
|
38
|
+
driver.uninstall name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/flick/screenshot.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Screenshot
|
2
|
-
|
2
|
+
|
3
3
|
attr_accessor :platform, :driver
|
4
|
-
|
4
|
+
|
5
5
|
def initialize options
|
6
6
|
Flick::Checker.platform options[:platform]
|
7
7
|
self.platform = options[:platform]
|
@@ -14,15 +14,19 @@ class Screenshot
|
|
14
14
|
end
|
15
15
|
setup
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
|
+
def android
|
19
|
+
platform == "android"
|
20
|
+
end
|
21
|
+
|
18
22
|
def screenshot
|
19
23
|
puts "Saving to #{driver.outdir}/#{driver.name}.png"
|
20
24
|
driver.screenshot driver.name
|
21
|
-
driver.pull_file "#{driver.dir_name}/#{driver.name}.png", driver.outdir if
|
25
|
+
driver.pull_file "#{driver.dir_name}/#{driver.name}.png", driver.outdir if android
|
22
26
|
end
|
23
|
-
|
27
|
+
|
24
28
|
private
|
25
|
-
|
29
|
+
|
26
30
|
def setup
|
27
31
|
driver.clear_files
|
28
32
|
end
|
data/lib/flick/simple_daemon.rb
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
# * The process becomes a session leader of a new session
|
19
19
|
# * The process becomes the process group leader of a new process group
|
20
20
|
# * The process has no controlling terminal
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# Optionally fork again and have the parent exit. This guarantes that
|
23
23
|
# the daemon is not a session leader nor can it acquire a controlling
|
24
24
|
# terminal (under SVR4)
|
@@ -28,13 +28,13 @@
|
|
28
28
|
# \_ simple daemon - writes out its pid to file
|
29
29
|
#
|
30
30
|
# Change the current working directory to / to avoid interfering with
|
31
|
-
# mounting and unmounting. By default don't bother to chdir("/") here
|
31
|
+
# mounting and unmounting. By default don't bother to chdir("/") here
|
32
32
|
# because we might to run inside APP_ROOT.
|
33
33
|
#
|
34
34
|
# Set file mode creation mask to 000 to allow creation of files with any
|
35
|
-
# required permission later. By default umask is whatever was set by the
|
36
|
-
# parent process at startup and can be set in config.ru and config_file,
|
37
|
-
# so making it 0000 and potentially exposing sensitive log data can be
|
35
|
+
# required permission later. By default umask is whatever was set by the
|
36
|
+
# parent process at startup and can be set in config.ru and config_file,
|
37
|
+
# so making it 0000 and potentially exposing sensitive log data can be
|
38
38
|
# bad policy.
|
39
39
|
#
|
40
40
|
# Close unneeded file descriptors inherited from the parent (there is no
|
@@ -46,8 +46,9 @@
|
|
46
46
|
# value of getpid() after step 3.
|
47
47
|
#
|
48
48
|
class SimpleDaemon
|
49
|
+
|
49
50
|
# In the directory where you want your daemon add a git submodule to
|
50
|
-
# your project and create a daemon launcher script:
|
51
|
+
# your project and create a daemon launcher script:
|
51
52
|
#
|
52
53
|
# #!/usr/bin/env ruby
|
53
54
|
#
|
@@ -74,14 +75,16 @@ class SimpleDaemon
|
|
74
75
|
# $ ps aux | grep "my daemon"
|
75
76
|
#
|
76
77
|
#
|
77
|
-
def self.daemonize!
|
78
|
+
def self.daemonize! out = '/dev/null', err = '/dev/null', safe = true
|
78
79
|
raise 'First fork failed' if (pid = fork) == -1
|
79
80
|
exit unless pid.nil?
|
80
81
|
Process.setsid
|
81
82
|
raise 'Second fork failed' if (pid = fork) == -1
|
82
83
|
exit unless pid.nil?
|
83
|
-
|
84
|
-
|
84
|
+
kill_pid
|
85
|
+
@file = Tempfile.new
|
86
|
+
@file.write Process.pid
|
87
|
+
@file.rewind
|
85
88
|
unless safe
|
86
89
|
Dir.chdir '/'
|
87
90
|
File.umask 0000
|
@@ -103,9 +106,12 @@ class SimpleDaemon
|
|
103
106
|
|
104
107
|
# Try and read the existing pid from the pid file and signal HUP to
|
105
108
|
# process.
|
106
|
-
def self.
|
107
|
-
|
108
|
-
|
109
|
+
def self.kill_pid
|
110
|
+
unless @file.nil?
|
111
|
+
opid = @file.read
|
112
|
+
Process.kill "HUP", opid
|
113
|
+
@file.unlink
|
114
|
+
end
|
109
115
|
rescue TypeError
|
110
116
|
$stdout.puts "#{pidfile} was empty: TypeError"
|
111
117
|
rescue Errno::ENOENT
|
data/lib/flick/system.rb
CHANGED
@@ -1,28 +1,48 @@
|
|
1
1
|
module Flick
|
2
2
|
module System
|
3
|
+
|
4
|
+
include Sys #load sys-proctable methods
|
5
|
+
|
3
6
|
def self.setup_system_dir dir_name
|
4
|
-
|
7
|
+
Dir.mkdir dir_name unless File.exists? dir_name
|
5
8
|
end
|
6
|
-
|
9
|
+
|
7
10
|
def self.clean_system_dir dir_name, udid
|
8
|
-
|
11
|
+
Dir.glob("#{dir_name}/*#{udid}*").each do |file|
|
12
|
+
File.delete file
|
13
|
+
end
|
9
14
|
end
|
10
|
-
|
11
|
-
def self.
|
12
|
-
|
15
|
+
|
16
|
+
def self.find_pid string
|
17
|
+
processes = ProcTable.ps.find_all { |x| x.cmdline.include? string }
|
18
|
+
processes.map { |p| p.pid } rescue []
|
13
19
|
end
|
14
|
-
|
15
|
-
def self.
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
|
21
|
+
def self.kill_pids pid_array
|
22
|
+
return if pid_array.empty?
|
23
|
+
pid_array.each { |p| Process.kill 'SIGKILL', p }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.process_running? string
|
27
|
+
pid = self.find_pid string
|
28
|
+
unless pid.empty?
|
29
|
+
puts "PROCESSING IS RUNNING!!!"
|
30
|
+
true
|
31
|
+
else
|
32
|
+
false
|
23
33
|
end
|
24
34
|
end
|
25
|
-
|
35
|
+
|
36
|
+
def self.kill_process type, udid
|
37
|
+
pids = self.find_pid "#{type}-#{udid}"
|
38
|
+
self.kill_pids pids
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.kill string
|
42
|
+
pids = self.find_pid string
|
43
|
+
self.kill_pids pids
|
44
|
+
end
|
45
|
+
|
26
46
|
def self.video_length file
|
27
47
|
(`ffmpeg -i #{file} 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//`).strip
|
28
48
|
end
|
data/lib/flick/version.rb
CHANGED
data/lib/flick/video.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Video
|
2
2
|
|
3
3
|
attr_accessor :action, :platform, :driver, :image_count, :seconds, :extended, :udid, :format
|
4
|
-
|
4
|
+
|
5
5
|
def initialize options
|
6
6
|
Flick::Checker.action options[:action]
|
7
7
|
Flick::Checker.platform options[:platform]
|
@@ -20,19 +20,19 @@ class Video
|
|
20
20
|
self.udid = self.driver.udid
|
21
21
|
self.format = options[:format]
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def android
|
25
25
|
platform == "android"
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def ios
|
29
29
|
platform == "ios"
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def run
|
33
33
|
self.send(action)
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def start
|
37
37
|
driver.clear_files
|
38
38
|
puts "\nStarting Recoder!!!"
|
@@ -49,7 +49,7 @@ class Video
|
|
49
49
|
start_screenshot_record
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def stop
|
54
54
|
puts "\nStopping Recorder!!!"
|
55
55
|
if driver.recordable?
|
@@ -60,99 +60,94 @@ class Video
|
|
60
60
|
sleep 1
|
61
61
|
driver.clear_files
|
62
62
|
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
66
|
def start_record
|
67
67
|
Flick::System.kill_process "video", udid
|
68
68
|
$0 = "flick-video-#{udid}"
|
69
|
-
SimpleDaemon.daemonize!
|
69
|
+
SimpleDaemon.daemonize!
|
70
70
|
command = -> do
|
71
|
-
driver.screenrecord "
|
71
|
+
driver.screenrecord "video-#{udid}-single"
|
72
72
|
end
|
73
73
|
command.call
|
74
74
|
end
|
75
|
-
|
76
|
-
def is_recording?
|
77
|
-
!(`pgrep -f #{udid}-`).empty?
|
78
|
-
end
|
79
|
-
|
75
|
+
|
80
76
|
def loop_record
|
81
77
|
Flick::System.kill_process "video", udid
|
82
78
|
$0 = "flick-video-#{udid}"
|
83
|
-
SimpleDaemon.daemonize!
|
79
|
+
SimpleDaemon.daemonize!
|
84
80
|
command = -> do
|
85
81
|
count = "%03d" % 1
|
86
82
|
loop do
|
87
|
-
unless
|
88
|
-
driver.screenrecord "
|
83
|
+
unless Flick::System.process_running? "#{udid}-"
|
84
|
+
driver.screenrecord "video-#{udid}-#{count}"
|
89
85
|
count.next!
|
90
86
|
end
|
91
87
|
end
|
92
88
|
end
|
93
89
|
command.call
|
94
90
|
end
|
95
|
-
|
91
|
+
|
96
92
|
def stop_record
|
97
93
|
Flick::System.kill_process "video", udid
|
98
94
|
sleep 5 #wait for video process to finish
|
99
|
-
driver.pull_files
|
100
|
-
files = (
|
95
|
+
driver.pull_files "video"
|
96
|
+
files = Dir.glob("#{driver.flick_dir}/video-#{udid}*.mp4")
|
101
97
|
return if files.empty?
|
102
98
|
files.each { |file| system("mp4box -cat #{file} #{driver.flick_dir}/#{driver.name}.mp4") }
|
103
99
|
puts "Saving to #{driver.outdir}/#{driver.name}.#{format}"
|
104
100
|
if format == "gif"
|
105
101
|
gif
|
106
102
|
else
|
107
|
-
|
103
|
+
File.rename "#{driver.flick_dir}/#{driver.name}.mp4", "#{driver.outdir}/#{driver.name}.mp4"
|
108
104
|
end
|
109
105
|
end
|
110
|
-
|
106
|
+
|
111
107
|
def start_screenshot_record
|
112
108
|
Flick::System.kill_process "screenshot", udid
|
113
109
|
puts "Process will stop after #{image_count} screenshots.\n"
|
114
110
|
$0 = "flick-screenshot-#{udid}"
|
115
|
-
SimpleDaemon.daemonize!
|
111
|
+
SimpleDaemon.daemonize!
|
116
112
|
command = -> do
|
117
113
|
count = "%03d" % 1
|
118
114
|
loop do
|
119
|
-
if count.to_i
|
120
|
-
driver.screenshot "
|
115
|
+
if count.to_i <= image_count
|
116
|
+
driver.screenshot "screenshot-#{udid}-#{count}"
|
121
117
|
count.next!; sleep seconds
|
122
118
|
else
|
123
|
-
|
124
|
-
self.send(format)
|
119
|
+
stop_screenshot_recording
|
125
120
|
break
|
126
121
|
end
|
127
122
|
end
|
128
123
|
end
|
129
124
|
command.call
|
130
125
|
end
|
131
|
-
|
132
|
-
def stop_screenshot_recording
|
133
|
-
|
134
|
-
`rm /tmp/#{udid}-pidfile >> /dev/null 2>&1`
|
135
|
-
driver.pull_files if android
|
126
|
+
|
127
|
+
def stop_screenshot_recording
|
128
|
+
driver.pull_files "screenshot" if android
|
136
129
|
puts "Saving to #{driver.outdir}/#{driver.name}.#{format}"
|
137
130
|
self.send(format)
|
138
131
|
end
|
139
|
-
|
132
|
+
|
140
133
|
def gif
|
141
134
|
convert_images_to_mp4 unless driver.recordable?
|
142
|
-
%x(
|
135
|
+
%x(ffmpeg -loglevel quiet -i #{driver.flick_dir}/#{driver.name}.mp4 -pix_fmt rgb24 #{driver.outdir}/#{driver.name}.gif)
|
143
136
|
end
|
144
|
-
|
137
|
+
|
145
138
|
def mp4
|
146
139
|
convert_images_to_mp4
|
147
|
-
|
140
|
+
File.rename "#{driver.flick_dir}/#{driver.name}.mp4", "#{driver.outdir}/#{driver.name}.mp4" unless format == "gif"
|
148
141
|
end
|
149
|
-
|
142
|
+
|
150
143
|
def convert_images_to_mp4
|
151
144
|
remove_zero_byte_images
|
152
|
-
%x(
|
145
|
+
%x(ffmpeg -loglevel quiet -framerate 1 -pattern_type glob -i '#{driver.flick_dir}/screenshot-#{udid}*.png' -c:v libx264 -pix_fmt yuv420p #{driver.flick_dir}/#{driver.name}.mp4)
|
153
146
|
end
|
154
|
-
|
147
|
+
|
155
148
|
def remove_zero_byte_images
|
156
|
-
|
149
|
+
Dir.glob("#{driver.flick_dir}/screenshot-#{udid}*.png").each do |f|
|
150
|
+
File.delete f if File.zero? f
|
151
|
+
end
|
157
152
|
end
|
158
153
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -166,6 +166,60 @@ dependencies:
|
|
166
166
|
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: 1.6.1
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: os
|
171
|
+
requirement: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - "~>"
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: 0.9.6
|
176
|
+
type: :runtime
|
177
|
+
prerelease: false
|
178
|
+
version_requirements: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - "~>"
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 0.9.6
|
183
|
+
- !ruby/object:Gem::Dependency
|
184
|
+
name: sys-proctable
|
185
|
+
requirement: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - "~>"
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '1.1'
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: 1.1.1
|
193
|
+
type: :runtime
|
194
|
+
prerelease: false
|
195
|
+
version_requirements: !ruby/object:Gem::Requirement
|
196
|
+
requirements:
|
197
|
+
- - "~>"
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
version: '1.1'
|
200
|
+
- - ">="
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: 1.1.1
|
203
|
+
- !ruby/object:Gem::Dependency
|
204
|
+
name: apktools
|
205
|
+
requirement: !ruby/object:Gem::Requirement
|
206
|
+
requirements:
|
207
|
+
- - "~>"
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: 0.7.1
|
210
|
+
- - ">="
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: 0.7.1
|
213
|
+
type: :runtime
|
214
|
+
prerelease: false
|
215
|
+
version_requirements: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - "~>"
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: 0.7.1
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: 0.7.1
|
169
223
|
description: A CLI with helpful QA tools for iOS and Android from the command line
|
170
224
|
email:
|
171
225
|
- justin.ison@gmail.com
|
@@ -192,6 +246,7 @@ files:
|
|
192
246
|
- lib/flick/info.rb
|
193
247
|
- lib/flick/ios.rb
|
194
248
|
- lib/flick/log.rb
|
249
|
+
- lib/flick/manager.rb
|
195
250
|
- lib/flick/screenshot.rb
|
196
251
|
- lib/flick/simple_daemon.rb
|
197
252
|
- lib/flick/system.rb
|
@@ -224,4 +279,3 @@ specification_version: 4
|
|
224
279
|
summary: A CLI to capture screenshots, video, logs, and device information for Android
|
225
280
|
(Devices & Emulators) and iOS (Devices).
|
226
281
|
test_files: []
|
227
|
-
has_rdoc:
|