├── .gitignore ├── src ├── ServiceProvider.php └── routes.php ├── composer.json ├── LICENSE ├── resources └── views │ ├── ios-manifest.blade.php │ └── ios-download.blade.php ├── README.md └── composer.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea/ 3 | vendor/ 4 | -------------------------------------------------------------------------------- /src/ServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadRoutesFrom(__DIR__.'/routes.php'); 15 | $this->loadViewsFrom(__DIR__ . '/../resources/views', 'ota-distribution-ios'); 16 | 17 | $this->publishes([ 18 | __DIR__.'/../resources/views' => resource_path('views/vendor/ota-distribution-ios'), 19 | ]); 20 | } 21 | 22 | /** 23 | * Register the application services. 24 | * 25 | * @return void 26 | */ 27 | public function register() 28 | { 29 | // 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pavankataria/laravel-ota-distribution-ios", 3 | "repositories": [ 4 | { 5 | "type": "vcs", 6 | "url": "https://github.com/pavankataria/laravel-ota-distribution-ios" 7 | } 8 | ], 9 | "description": "This package creates the html download views and routes required for both uploading ios builds and the creation of manifest files ready for downloading the ios builds.", 10 | "keywords": ["laravel", "ota", "ios", "distribution", "over the air", "ipa"], 11 | "type": "library", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Pavan Kataria", 16 | "email": "info@pavankataria.com" 17 | } 18 | ], 19 | "minimum-stability": "dev", 20 | "require": { 21 | "php": ">=5.5.9", 22 | "illuminate/support": "8.*", 23 | "nesbot/carbon": "^2.53.1" 24 | }, 25 | "autoload": { 26 | "psr-4" : { 27 | "PavanKataria\\OtaDistributionIos\\" : "src/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 pavankataria 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /resources/views/ios-manifest.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | assets 9 | 10 | 11 | kind 12 | software-package 13 | url 14 | {{ $buildUrlRoute }} 15 | 16 | 17 | kind 18 | display-image 19 | url 20 | {{ $publicUrl }}/image.57x57.jpg 21 | {{--{{ $publicUrl }}/image57--}} 22 | 23 | 24 | kind 25 | full-size-image 26 | url 27 | {{ $publicUrl }}/image.512x512.jpg 28 | {{--{{ $publicUrl }}/image512--}} 29 | 30 | 31 | metadata 32 | 33 | bundle-identifier 34 | <\com.domain.projectname identical to the app's bundle identifier> 35 | bundle-version 36 | {{ $bundleVersionNumber }} 37 | kind 38 | software 39 | title 40 | <\Insert Application Name> 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /resources/views/ios-download.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [BETA_NAME] [BETA_VERSION] 7 | 17 | 18 | 19 | 20 |
21 | 22 | [BETA_ICON] 23 | 24 |

Install Link

25 | 26 | 27 | 28 |

Link didn't work?
29 | Make sure you're visiting this page on your device, not your computer.

30 | 31 |

Last Updated: {{ $appLastUpdated }}

32 | 33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Laravel OTA (Over-The-Air) Distribution for iOS 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE.md) 5 | 7 | 8 | The package creates the necessary files and routes on your server to cater for the upload of iOS .ipa files and provision the installation of those builds on iOS devices. 9 | 10 | ### Great, how does it work? 11 | 12 | The package allows an integration tool to submit an iOS build to your server - where you can act as the host - the package’s service provider creates the routes that 1) handle the submission of the build which in turn create the necessary manifest files, views, and the download page required for over the air distribution for ios devices, and routes to download the build using those generated files. 13 | 14 | Note, since iOS 9, over-the-air distribution requires the https protocol or installation will fail. 15 | 16 | ## Installation 17 | 18 | Require this package with composer: 19 | 20 | ```shell 21 | composer require "pavankataria/laravel-ota-distribution-ios":"dev-master" 22 | ``` 23 | 24 | After updating composer, add the ServiceProvider to the providers array in config/app.php 25 | 26 | ### Laravel 5.x: 27 | 28 | ```php 29 | PavanKataria\OtaDistributionIos\ServiceProvider::class, 30 | ``` 31 | 32 | Run the publish command to finish with the installation, copy the views to the views vendor directory. The routes that serve the build use these views. 33 | 34 | ```shell 35 | php artisan vendor:publish --provider="PavanKataria\OtaDistributionIos\ServiceProvider" 36 | ``` 37 | 38 | ### Lumen: 39 | 40 | For Lumen, register a different Provider in `bootstrap/app.php`: 41 | 42 | ### License 43 | 44 | The Laravel OTA Distribution for iOS package is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) 45 | 46 | [ico-version]: https://img.shields.io/packagist/v/pavankataria/laravel-ota-distribution-ios.svg?style=flat-square 47 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 48 | [ico-travis]: https://img.shields.io/travis/pavankataria/laravel-ota-distribution-ios/master.svg?style=flat-square 49 | [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/pavankataria/laravel-ota-distribution-ios.svg?style=flat-square 50 | [ico-code-quality]: https://img.shields.io/scrutinizer/g/pavankataria/laravel-ota-distribution-ios.svg?style=flat-square 51 | [ico-downloads]: https://img.shields.io/packagist/dt/pavankataria/laravel-ota-distribution-ios.svg?style=flat-square 52 | 53 | [link-packagist]: https://packagist.org/packages/pavankataria/laravel-ota-distribution-ios 54 | [link-travis]: https://travis-ci.org/pavankataria/laravel-ota-distribution-ios 55 | [link-scrutinizer]: https://scrutinizer-ci.com/g/pavankataria/laravel-ota-distribution-ios 56 | [link-code-quality]: https://scrutinizer-ci.com/g/pavankataria/laravel-ota-distribution-ios 57 | [link-downloads]: https://packagist.org/packages/pavankataria/laravel-ota-distribution-ios 58 | [link-author]: https://github.com/pavankataria 59 | [link-contributors]: ../../contributors 60 | -------------------------------------------------------------------------------- /src/routes.php: -------------------------------------------------------------------------------- 1 | input('build_version_number'); 11 | echo "branch: {$branch}"; 12 | echo "\nfile: {$file}"; 13 | echo "\nsize of file: {$file->getSize()}"; 14 | echo "\nbundle version number: " . $bundleVersionNumber; 15 | 16 | $appLastUpdated = Carbon::now(); 17 | $pathToBuildDirectory = "builds"; 18 | 19 | $iosManifestFileContents = view('ota-distribution-ios::ios-manifest') 20 | ->with('buildUrlRoute', $buildUrlRoute) 21 | ->with('publicUrl', $publicUrl) 22 | ->with('bundleVersionNumber', $bundleVersionNumber) 23 | ->render(); 24 | 25 | //Render the iOS view 26 | $iosDownloadFileContents = view('ota-distribution-ios::ios-download') 27 | ->with('appLastUpdated', $appLastUpdated) 28 | ->with('appVersion', $bundleVersionNumber) 29 | ->with('urlToManifestFile', route('builds.manifest')) 30 | ->render(); 31 | 32 | //Creates files and places them in a latest folder. 33 | $latestBuildPath = "{$pathToBuildDirectory}/latest"; 34 | Storage::put("{$latestBuildPath}/manifest.plist", $iosManifestFileContents); 35 | Storage::put("{$latestBuildPath}/download.html", $iosDownloadFileContents); 36 | $file->storeAs("{$latestBuildPath}", "build.ipa"); 37 | 38 | //Makes duplicate files in a separate bundle version folder for versioning. 39 | $bundleVersionPath = "{$pathToBuildDirectory}/{$bundleVersionNumber}"; 40 | Storage::put("{$bundleVersionPath}/manifest.plist", $iosManifestFileContents); 41 | Storage::put("{$bundleVersionPath}/download.html", $iosDownloadFileContents); 42 | $file->storeAs($bundleVersionPath, "build.ipa"); 43 | }); 44 | 45 | /** 46 | * A call to this request will search the directory for existing installable builds 47 | * and displays a message if none are found. If a build is found then a download 48 | * link is shown allowing the user to install the app from their iOS devices. 49 | * 50 | * @return string 51 | */ 52 | Route::get('/download', function(){ 53 | $directory = "builds/latest"; 54 | $buildFile = Storage::exists("{$directory}/download.html"); 55 | if ($buildFile == false) { 56 | //TODO: Return a view instead 57 | return "There are no builds available"; 58 | } 59 | return Storage::get("{$directory}/download.html"); 60 | }); 61 | 62 | //TODO: Give this route a name of builds/latest 63 | Route::get('api/build', function() { 64 | $directory = "builds/latest"; 65 | $buildFile = Storage::exists("{$directory}/build.ipa"); 66 | if ($buildFile == false) { 67 | return "There currently are no builds available"; 68 | } 69 | return Storage::get("{$directory}/build.ipa"); 70 | }); 71 | 72 | 73 | 74 | //Route::get('/api/builds/latest/download') 75 | 76 | /** 77 | * This exposed route is for the iOS installation process which requires the manifest file 78 | * to be exposed. This manifest file contains the details for the download of image 79 | * urls, and ipa build files. 80 | * 81 | * @return mixed 82 | */ 83 | Route::get('/api/manifest', function() { 84 | return Storage::get("builds/latest/manifest.plist"); 85 | })->name("builds.manifest"); -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "afce8df0afe832c0426a83d1c3ba55b7", 8 | "packages": [ 9 | { 10 | "name": "doctrine/inflector", 11 | "version": "dev-master", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/doctrine/inflector.git", 15 | "reference": "803a2ed9fea02f9ca47cd45395089fe78769a392" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/803a2ed9fea02f9ca47cd45395089fe78769a392", 20 | "reference": "803a2ed9fea02f9ca47cd45395089fe78769a392", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": ">=5.3.2" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "4.*" 28 | }, 29 | "type": "library", 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "1.1.x-dev" 33 | } 34 | }, 35 | "autoload": { 36 | "psr-0": { 37 | "Doctrine\\Common\\Inflector\\": "lib/" 38 | } 39 | }, 40 | "notification-url": "https://packagist.org/downloads/", 41 | "license": [ 42 | "MIT" 43 | ], 44 | "authors": [ 45 | { 46 | "name": "Roman Borschel", 47 | "email": "roman@code-factory.org" 48 | }, 49 | { 50 | "name": "Benjamin Eberlei", 51 | "email": "kontakt@beberlei.de" 52 | }, 53 | { 54 | "name": "Guilherme Blanco", 55 | "email": "guilhermeblanco@gmail.com" 56 | }, 57 | { 58 | "name": "Jonathan Wage", 59 | "email": "jonwage@gmail.com" 60 | }, 61 | { 62 | "name": "Johannes Schmitt", 63 | "email": "schmittjoh@gmail.com" 64 | } 65 | ], 66 | "description": "Common String Manipulations with regard to casing and singular/plural rules.", 67 | "homepage": "http://www.doctrine-project.org", 68 | "keywords": [ 69 | "inflection", 70 | "pluralize", 71 | "singularize", 72 | "string" 73 | ], 74 | "time": "2016-05-12 17:23:41" 75 | }, 76 | { 77 | "name": "illuminate/contracts", 78 | "version": "5.4.x-dev", 79 | "source": { 80 | "type": "git", 81 | "url": "https://github.com/illuminate/contracts.git", 82 | "reference": "dd256891c80fd94a58ab83d7989d6da2f50e30ea" 83 | }, 84 | "dist": { 85 | "type": "zip", 86 | "url": "https://api.github.com/repos/illuminate/contracts/zipball/dd256891c80fd94a58ab83d7989d6da2f50e30ea", 87 | "reference": "dd256891c80fd94a58ab83d7989d6da2f50e30ea", 88 | "shasum": "" 89 | }, 90 | "require": { 91 | "php": ">=5.6.4" 92 | }, 93 | "type": "library", 94 | "extra": { 95 | "branch-alias": { 96 | "dev-master": "5.4-dev" 97 | } 98 | }, 99 | "autoload": { 100 | "psr-4": { 101 | "Illuminate\\Contracts\\": "" 102 | } 103 | }, 104 | "notification-url": "https://packagist.org/downloads/", 105 | "license": [ 106 | "MIT" 107 | ], 108 | "authors": [ 109 | { 110 | "name": "Taylor Otwell", 111 | "email": "taylor@laravel.com" 112 | } 113 | ], 114 | "description": "The Illuminate Contracts package.", 115 | "homepage": "https://laravel.com", 116 | "time": "2017-02-21 14:21:59" 117 | }, 118 | { 119 | "name": "illuminate/support", 120 | "version": "5.4.x-dev", 121 | "source": { 122 | "type": "git", 123 | "url": "https://github.com/illuminate/support.git", 124 | "reference": "20c703419244557c10d9b035b205078fcb99f739" 125 | }, 126 | "dist": { 127 | "type": "zip", 128 | "url": "https://api.github.com/repos/illuminate/support/zipball/20c703419244557c10d9b035b205078fcb99f739", 129 | "reference": "20c703419244557c10d9b035b205078fcb99f739", 130 | "shasum": "" 131 | }, 132 | "require": { 133 | "doctrine/inflector": "~1.0", 134 | "ext-mbstring": "*", 135 | "illuminate/contracts": "5.4.*", 136 | "paragonie/random_compat": "~1.4|~2.0", 137 | "php": ">=5.6.4" 138 | }, 139 | "replace": { 140 | "tightenco/collect": "self.version" 141 | }, 142 | "suggest": { 143 | "illuminate/filesystem": "Required to use the composer class (5.2.*).", 144 | "symfony/process": "Required to use the composer class (~3.2).", 145 | "symfony/var-dumper": "Required to use the dd function (~3.2)." 146 | }, 147 | "type": "library", 148 | "extra": { 149 | "branch-alias": { 150 | "dev-master": "5.4-dev" 151 | } 152 | }, 153 | "autoload": { 154 | "psr-4": { 155 | "Illuminate\\Support\\": "" 156 | }, 157 | "files": [ 158 | "helpers.php" 159 | ] 160 | }, 161 | "notification-url": "https://packagist.org/downloads/", 162 | "license": [ 163 | "MIT" 164 | ], 165 | "authors": [ 166 | { 167 | "name": "Taylor Otwell", 168 | "email": "taylor@laravel.com" 169 | } 170 | ], 171 | "description": "The Illuminate Support package.", 172 | "homepage": "https://laravel.com", 173 | "time": "2017-03-05 16:32:05" 174 | }, 175 | { 176 | "name": "nesbot/carbon", 177 | "version": "dev-master", 178 | "source": { 179 | "type": "git", 180 | "url": "https://github.com/briannesbitt/Carbon.git", 181 | "reference": "926aee5ab38c2868816aa760f862a85ad01cb61a" 182 | }, 183 | "dist": { 184 | "type": "zip", 185 | "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/926aee5ab38c2868816aa760f862a85ad01cb61a", 186 | "reference": "926aee5ab38c2868816aa760f862a85ad01cb61a", 187 | "shasum": "" 188 | }, 189 | "require": { 190 | "php": ">=5.3.0", 191 | "symfony/translation": "~2.6 || ~3.0" 192 | }, 193 | "require-dev": { 194 | "friendsofphp/php-cs-fixer": "~2", 195 | "phpunit/phpunit": "~4.0 || ~5.0" 196 | }, 197 | "type": "library", 198 | "extra": { 199 | "branch-alias": { 200 | "dev-master": "1.23-dev" 201 | } 202 | }, 203 | "autoload": { 204 | "psr-4": { 205 | "Carbon\\": "src/Carbon/" 206 | } 207 | }, 208 | "notification-url": "https://packagist.org/downloads/", 209 | "license": [ 210 | "MIT" 211 | ], 212 | "authors": [ 213 | { 214 | "name": "Brian Nesbitt", 215 | "email": "brian@nesbot.com", 216 | "homepage": "http://nesbot.com" 217 | } 218 | ], 219 | "description": "A simple API extension for DateTime.", 220 | "homepage": "http://carbon.nesbot.com", 221 | "keywords": [ 222 | "date", 223 | "datetime", 224 | "time" 225 | ], 226 | "time": "2017-02-06 22:02:47" 227 | }, 228 | { 229 | "name": "paragonie/random_compat", 230 | "version": "v2.0.9", 231 | "source": { 232 | "type": "git", 233 | "url": "https://github.com/paragonie/random_compat.git", 234 | "reference": "6968531206671f94377b01dc7888d5d1b858a01b" 235 | }, 236 | "dist": { 237 | "type": "zip", 238 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/6968531206671f94377b01dc7888d5d1b858a01b", 239 | "reference": "6968531206671f94377b01dc7888d5d1b858a01b", 240 | "shasum": "" 241 | }, 242 | "require": { 243 | "php": ">=5.2.0" 244 | }, 245 | "require-dev": { 246 | "phpunit/phpunit": "4.*|5.*" 247 | }, 248 | "suggest": { 249 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 250 | }, 251 | "type": "library", 252 | "autoload": { 253 | "files": [ 254 | "lib/random.php" 255 | ] 256 | }, 257 | "notification-url": "https://packagist.org/downloads/", 258 | "license": [ 259 | "MIT" 260 | ], 261 | "authors": [ 262 | { 263 | "name": "Paragon Initiative Enterprises", 264 | "email": "security@paragonie.com", 265 | "homepage": "https://paragonie.com" 266 | } 267 | ], 268 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 269 | "keywords": [ 270 | "csprng", 271 | "pseudorandom", 272 | "random" 273 | ], 274 | "time": "2017-03-03T20:43:42+00:00" 275 | }, 276 | { 277 | "name": "symfony/polyfill-mbstring", 278 | "version": "dev-master", 279 | "source": { 280 | "type": "git", 281 | "url": "https://github.com/symfony/polyfill-mbstring.git", 282 | "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" 283 | }, 284 | "dist": { 285 | "type": "zip", 286 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", 287 | "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", 288 | "shasum": "" 289 | }, 290 | "require": { 291 | "php": ">=5.3.3" 292 | }, 293 | "suggest": { 294 | "ext-mbstring": "For best performance" 295 | }, 296 | "type": "library", 297 | "extra": { 298 | "branch-alias": { 299 | "dev-master": "1.3-dev" 300 | } 301 | }, 302 | "autoload": { 303 | "psr-4": { 304 | "Symfony\\Polyfill\\Mbstring\\": "" 305 | }, 306 | "files": [ 307 | "bootstrap.php" 308 | ] 309 | }, 310 | "notification-url": "https://packagist.org/downloads/", 311 | "license": [ 312 | "MIT" 313 | ], 314 | "authors": [ 315 | { 316 | "name": "Nicolas Grekas", 317 | "email": "p@tchwork.com" 318 | }, 319 | { 320 | "name": "Symfony Community", 321 | "homepage": "https://symfony.com/contributors" 322 | } 323 | ], 324 | "description": "Symfony polyfill for the Mbstring extension", 325 | "homepage": "https://symfony.com", 326 | "keywords": [ 327 | "compatibility", 328 | "mbstring", 329 | "polyfill", 330 | "portable", 331 | "shim" 332 | ], 333 | "time": "2016-11-14 01:06:16" 334 | }, 335 | { 336 | "name": "symfony/translation", 337 | "version": "dev-master", 338 | "source": { 339 | "type": "git", 340 | "url": "https://github.com/symfony/translation.git", 341 | "reference": "987e8740b947320ce8431b4d48da97ec5c05c66c" 342 | }, 343 | "dist": { 344 | "type": "zip", 345 | "url": "https://api.github.com/repos/symfony/translation/zipball/987e8740b947320ce8431b4d48da97ec5c05c66c", 346 | "reference": "987e8740b947320ce8431b4d48da97ec5c05c66c", 347 | "shasum": "" 348 | }, 349 | "require": { 350 | "php": ">=5.5.9", 351 | "symfony/polyfill-mbstring": "~1.0" 352 | }, 353 | "conflict": { 354 | "symfony/config": "<2.8", 355 | "symfony/yaml": "<3.3" 356 | }, 357 | "require-dev": { 358 | "psr/log": "~1.0", 359 | "symfony/config": "~2.8|~3.0", 360 | "symfony/intl": "^2.8.18|^3.2.5", 361 | "symfony/yaml": "~3.3" 362 | }, 363 | "suggest": { 364 | "psr/log": "To use logging capability in translator", 365 | "symfony/config": "", 366 | "symfony/yaml": "" 367 | }, 368 | "type": "library", 369 | "extra": { 370 | "branch-alias": { 371 | "dev-master": "3.3-dev" 372 | } 373 | }, 374 | "autoload": { 375 | "psr-4": { 376 | "Symfony\\Component\\Translation\\": "" 377 | }, 378 | "exclude-from-classmap": [ 379 | "/Tests/" 380 | ] 381 | }, 382 | "notification-url": "https://packagist.org/downloads/", 383 | "license": [ 384 | "MIT" 385 | ], 386 | "authors": [ 387 | { 388 | "name": "Fabien Potencier", 389 | "email": "fabien@symfony.com" 390 | }, 391 | { 392 | "name": "Symfony Community", 393 | "homepage": "https://symfony.com/contributors" 394 | } 395 | ], 396 | "description": "Symfony Translation Component", 397 | "homepage": "https://symfony.com", 398 | "time": "2017-03-06 19:18:14" 399 | } 400 | ], 401 | "packages-dev": [], 402 | "aliases": [], 403 | "minimum-stability": "dev", 404 | "stability-flags": [], 405 | "prefer-stable": false, 406 | "prefer-lowest": false, 407 | "platform": { 408 | "php": ">=5.5.9" 409 | }, 410 | "platform-dev": [] 411 | } 412 | --------------------------------------------------------------------------------