Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
0f505fbf
Commit
0f505fbf
authored
Jan 22, 2016
by
Matt Perry
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1263 from mpcomplete/apk.tool
'flutter apk' now supports dynamically registered services.
parents
f88c945e
dcbb4960
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
160 additions
and
62 deletions
+160
-62
AndroidManifest.xml
examples/fitness/apk/AndroidManifest.xml
+3
-3
FitnessApplication.java
...tness/apk/src/org/domokit/fitness/FitnessApplication.java
+0
-36
flutter.yaml
examples/fitness/flutter.yaml
+2
-0
main.dart
examples/fitness/lib/main.dart
+1
-0
pubspec.yaml
packages/flutter/pubspec.yaml
+2
-2
artifacts.dart
packages/flutter_tools/lib/src/artifacts.dart
+43
-12
apk.dart
packages/flutter_tools/lib/src/commands/apk.dart
+96
-9
config.yaml
packages/gcm/lib/apk/config.yaml
+13
-0
No files found.
examples/fitness/apk/AndroidManifest.xml
View file @
0f505fbf
...
...
@@ -13,12 +13,12 @@
<uses-permission
android:name=
"com.google.android.c2dm.permission.RECEIVE"
/>
<!-- Supposedly this permission prevents other apps from receiving our
messages, but it doesn't seem to have any effect. -->
<permission
android:name=
"org.domokit.
sky.shell
.permission.C2D_MESSAGE"
<permission
android:name=
"org.domokit.
fitness
.permission.C2D_MESSAGE"
android:protectionLevel=
"signature"
/>
<uses-permission
android:name=
"org.domokit.
sky.shell
.permission.C2D_MESSAGE"
/>
<uses-permission
android:name=
"org.domokit.
fitness
.permission.C2D_MESSAGE"
/>
<!-- end for GCM -->
<application
android:icon=
"@mipmap/ic_launcher"
android:label=
"Fitness"
android:name=
"org.domokit.
fitness.Fitness
Application"
>
<application
android:icon=
"@mipmap/ic_launcher"
android:label=
"Fitness"
android:name=
"org.domokit.
sky.shell.Sky
Application"
>
<activity
android:configChanges=
"orientation|keyboardHidden|keyboard|screenSize"
android:hardwareAccelerated=
"true"
android:launchMode=
"singleTask"
android:name=
"org.domokit.sky.shell.SkyActivity"
android:theme=
"@android:style/Theme.Black.NoTitleBar"
>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
...
...
examples/fitness/apk/src/org/domokit/fitness/FitnessApplication.java
deleted
100644 → 0
View file @
f88c945e
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package
org
.
domokit
.
fitness
;
import
android.content.Context
;
import
org.chromium.mojo.system.Core
;
import
org.chromium.mojo.system.MessagePipeHandle
;
import
org.chromium.mojom.gcm.GcmService
;
import
org.domokit.gcm.RegistrationIntentService
;
import
org.domokit.sky.shell.ServiceFactory
;
import
org.domokit.sky.shell.ServiceRegistry
;
import
org.domokit.sky.shell.SkyApplication
;
/**
* Sky implementation of {@link android.app.Application}, managing application-level global
* state and initializations.
*/
public
class
FitnessApplication
extends
SkyApplication
{
/**
* Override this function to register more services.
*/
protected
void
onServiceRegistryAvailable
(
ServiceRegistry
registry
)
{
super
.
onServiceRegistryAvailable
(
registry
);
registry
.
register
(
GcmService
.
MANAGER
.
getName
(),
new
ServiceFactory
()
{
@Override
public
void
connectToService
(
Context
context
,
Core
core
,
MessagePipeHandle
pipe
)
{
GcmService
.
MANAGER
.
bind
(
new
RegistrationIntentService
.
MojoService
(
context
),
pipe
);
}
});
}
}
examples/fitness/flutter.yaml
View file @
0f505fbf
...
...
@@ -13,3 +13,5 @@ material-design-icons:
-
name
:
navigation/close
-
name
:
navigation/menu
-
name
:
navigation/more_vert
services
:
-
gcm
examples/fitness/lib/main.dart
View file @
0f505fbf
...
...
@@ -175,5 +175,6 @@ initGcm() async {
}
main
()
{
initGcm
();
runApp
(
new
FitnessApp
());
}
packages/flutter/pubspec.yaml
View file @
0f505fbf
...
...
@@ -8,8 +8,8 @@ dependencies:
collection
:
'
>=1.1.3
<2.0.0'
intl
:
'
>=0.12.4+2
<0.13.0'
material_design_icons
:
'
>=0.0.3
<0.1.0'
sky_engine
:
0.0.8
5
sky_services
:
0.0.8
5
sky_engine
:
0.0.8
6
sky_services
:
0.0.8
6
vector_math
:
'
>=1.4.5
<2.0.0'
quiver
:
'
>=0.21.4
<0.22.0'
...
...
packages/flutter_tools/lib/src/artifacts.dart
View file @
0f505fbf
...
...
@@ -47,7 +47,7 @@ enum ArtifactType {
snapshot
,
shell
,
mojo
,
androidClasses
Dex
,
androidClasses
Jar
,
androidIcuData
,
androidKeystore
,
androidLibSkyShell
,
...
...
@@ -124,8 +124,8 @@ class ArtifactStore {
),
const
Artifact
.
_
(
name:
'Compiled Java code'
,
fileName:
'classes.dex'
,
type:
ArtifactType
.
androidClasses
Dex
,
fileName:
'classes.dex
.jar
'
,
type:
ArtifactType
.
androidClasses
Jar
,
targetPlatform:
TargetPlatform
.
android
),
const
Artifact
.
_
(
...
...
@@ -219,14 +219,12 @@ class ArtifactStore {
);
}
/// Download the artifacts.zip archive for the given platform from GCS
/// and extract it to the local cache.
static
Future
_doDownloadArtifactsFromZip
(
String
platform
)
async
{
String
url
=
getCloudStorageBaseUrl
(
platform
)
+
'artifacts.zip'
;
/// Download a file from the given URL and return the bytes.
static
Future
<
List
<
int
>>
_downloadFile
(
Uri
url
)
async
{
logging
.
info
(
'Downloading
$url
.'
);
HttpClient
httpClient
=
new
HttpClient
();
HttpClientRequest
request
=
await
httpClient
.
getUrl
(
Uri
.
parse
(
url
)
);
HttpClientRequest
request
=
await
httpClient
.
getUrl
(
url
);
HttpClientResponse
response
=
await
request
.
close
();
logging
.
fine
(
'Received response statusCode=
${response.statusCode}
'
);
if
(
response
.
statusCode
!=
200
)
...
...
@@ -237,13 +235,29 @@ class ArtifactStore {
responseBody
.
add
(
chunk
);
}
Archive
archive
=
new
ZipDecoder
().
decodeBytes
(
responseBody
.
takeBytes
());
return
responseBody
.
takeBytes
();
}
/// Download a file from the given url and write it to the cache.
static
Future
_downloadFileToCache
(
Uri
url
,
File
cachedFile
)
async
{
if
(!
cachedFile
.
parent
.
existsSync
())
cachedFile
.
parent
.
createSync
(
recursive:
true
);
List
<
int
>
fileBytes
=
await
_downloadFile
(
url
);
cachedFile
.
writeAsBytesSync
(
fileBytes
,
flush:
true
);
}
/// Download the artifacts.zip archive for the given platform from GCS
/// and extract it to the local cache.
static
Future
_doDownloadArtifactsFromZip
(
String
platform
)
async
{
String
url
=
getCloudStorageBaseUrl
(
platform
)
+
'artifacts.zip'
;
List
<
int
>
zipBytes
=
await
_downloadFile
(
Uri
.
parse
(
url
));
Archive
archive
=
new
ZipDecoder
().
decodeBytes
(
zipBytes
);
Directory
cacheDir
=
_getCacheDirForPlatform
(
platform
);
for
(
ArchiveFile
archiveFile
in
archive
)
{
File
cacheFile
=
new
File
(
path
.
join
(
cacheDir
.
path
,
archiveFile
.
name
));
IOSink
sink
=
cacheFile
.
openWrite
();
sink
.
add
(
archiveFile
.
content
);
await
sink
.
close
();
cacheFile
.
writeAsBytesSync
(
archiveFile
.
content
,
flush:
true
);
}
for
(
Artifact
artifact
in
knownArtifacts
)
{
...
...
@@ -306,6 +320,23 @@ class ArtifactStore {
return
cachedFile
.
path
;
}
static
Future
<
String
>
getThirdPartyFile
(
String
urlStr
,
String
cacheSubdir
)
async
{
Uri
url
=
Uri
.
parse
(
urlStr
);
Directory
baseDir
=
_getBaseCacheDir
();
Directory
cacheDir
=
new
Directory
(
path
.
join
(
baseDir
.
path
,
'third_party'
,
cacheSubdir
));
File
cachedFile
=
new
File
(
path
.
join
(
cacheDir
.
path
,
url
.
pathSegments
[
url
.
pathSegments
.
length
-
1
]));
if
(!
cachedFile
.
existsSync
())
{
await
_downloadFileToCache
(
url
,
cachedFile
);
if
(!
cachedFile
.
existsSync
())
{
logging
.
severe
(
'Unable to fetch third-party artifact:
$url
'
);
throw
new
ProcessExit
(
2
);
}
}
return
cachedFile
.
path
;
}
static
void
clear
()
{
Directory
cacheDir
=
_getBaseCacheDir
();
logging
.
fine
(
'Clearing cache directory
${cacheDir.path}
'
);
...
...
packages/flutter_tools/lib/src/commands/apk.dart
View file @
0f505fbf
...
...
@@ -3,9 +3,11 @@
// found in the LICENSE file.
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'package:path/path.dart'
as
path
;
import
'package:yaml/yaml.dart'
;
import
'../artifacts.dart'
;
import
'../base/file_system.dart'
;
...
...
@@ -21,6 +23,9 @@ const String _kDefaultAndroidManifestPath = 'apk/AndroidManifest.xml';
const
String
_kDefaultOutputPath
=
'build/app.apk'
;
const
String
_kDefaultResourcesPath
=
'apk/res'
;
const
String
_kFlutterManifestPath
=
'flutter.yaml'
;
const
String
_kPubspecYamlPath
=
'pubspec.yaml'
;
// Alias of the key provided in the Chromium debug keystore
const
String
_kDebugKeystoreKeyAlias
=
"chromiumdebugkey"
;
...
...
@@ -56,6 +61,7 @@ class _ApkBuilder {
File
_androidJar
;
File
_aapt
;
File
_dx
;
File
_zipalign
;
String
_jarsigner
;
...
...
@@ -64,12 +70,25 @@ class _ApkBuilder {
String
buildTools
=
'
$androidSdk
/build-tools/
$_kBuildToolsVersion
'
;
_aapt
=
new
File
(
'
$buildTools
/aapt'
);
_dx
=
new
File
(
'
$buildTools
/dx'
);
_zipalign
=
new
File
(
'
$buildTools
/zipalign'
);
_jarsigner
=
'jarsigner'
;
}
bool
checkSdkPath
()
{
return
(
_androidJar
.
existsSync
()
&&
_aapt
.
existsSync
()
&&
_zipalign
.
existsSync
());
return
(
_androidJar
.
existsSync
()
&&
_aapt
.
existsSync
()
&&
_dx
.
existsSync
()
&&
_zipalign
.
existsSync
());
}
void
compileClassesDex
(
File
classesDex
,
List
<
File
>
jars
)
{
List
<
String
>
packageArgs
=
[
_dx
.
path
,
'--dex'
,
'--force-jumbo'
,
'--output'
,
classesDex
.
path
];
packageArgs
.
addAll
(
jars
.
map
((
File
f
)
=>
f
.
path
));
runCheckedSync
(
packageArgs
);
}
void
package
(
File
outputApk
,
File
androidManifest
,
Directory
assets
,
Directory
artifacts
,
Directory
resources
)
{
...
...
@@ -106,12 +125,21 @@ class _ApkComponents {
Directory
androidSdk
;
File
manifest
;
File
icuData
;
File
classesDex
;
List
<
File
>
jars
;
List
<
Map
<
String
,
String
>>
services
=
[];
File
libSkyShell
;
File
debugKeystore
;
Directory
resources
;
}
// TODO(mpcomplete): find a better home for this.
dynamic
_loadYamlFile
(
String
path
)
{
if
(!
FileSystemEntity
.
isFileSync
(
path
))
return
null
;
String
manifestString
=
new
File
(
path
).
readAsStringSync
();
return
loadYaml
(
manifestString
);
}
class
ApkCommand
extends
FlutterCommand
{
final
String
name
=
'apk'
;
final
String
description
=
'Build an Android APK package.'
;
...
...
@@ -151,6 +179,36 @@ class ApkCommand extends FlutterCommand {
help:
'Password for the entry within the keystore.'
);
}
Future
_findServices
(
_ApkComponents
components
)
async
{
if
(!
ArtifactStore
.
isPackageRootValid
)
return
;
dynamic
manifest
=
_loadYamlFile
(
_kFlutterManifestPath
);
if
(
manifest
[
'services'
]
==
null
)
return
;
for
(
String
service
in
manifest
[
'services'
])
{
String
serviceRoot
=
'
${ArtifactStore.packageRoot}
/
$service
/apk'
;
dynamic
serviceConfig
=
_loadYamlFile
(
'
$serviceRoot
/config.yaml'
);
if
(
serviceConfig
==
null
||
serviceConfig
[
'jars'
]
==
null
)
continue
;
components
.
services
.
addAll
(
serviceConfig
[
'services'
]);
for
(
String
jar
in
serviceConfig
[
'jars'
])
{
// Jar might refer to an android SDK jar, or URL to download.
if
(
jar
.
startsWith
(
"android-sdk:"
))
{
jar
=
jar
.
replaceAll
(
'android-sdk:'
,
'
${components.androidSdk.path}
/'
);
components
.
jars
.
add
(
new
File
(
jar
));
}
else
if
(
jar
.
startsWith
(
"http"
))
{
String
cachePath
=
await
ArtifactStore
.
getThirdPartyFile
(
jar
,
service
);
components
.
jars
.
add
(
new
File
(
cachePath
));
}
else
{
logging
.
severe
(
'Service depends on a jar in an unrecognized format:
$jar
'
);
throw
new
ProcessExit
(
2
);
}
}
}
}
Future
<
_ApkComponents
>
_findApkComponents
(
BuildConfiguration
config
)
async
{
String
androidSdkPath
;
List
<
String
>
artifactPaths
;
...
...
@@ -158,7 +216,7 @@ class ApkCommand extends FlutterCommand {
androidSdkPath
=
'
${runner.enginePath}
/third_party/android_tools/sdk'
;
artifactPaths
=
[
'
${runner.enginePath}
/third_party/icu/android/icudtl.dat'
,
'
${config.buildDir}
/gen/sky/shell/shell/classes.dex'
,
'
${config.buildDir}
/gen/sky/shell/shell/classes.dex
.jar
'
,
'
${config.buildDir}
/gen/sky/shell/shell/shell/libs/armeabi-v7a/libsky_shell.so'
,
'
${runner.enginePath}
/build/android/ant/chromium-debug.keystore'
,
];
...
...
@@ -169,7 +227,7 @@ class ApkCommand extends FlutterCommand {
}
List
<
ArtifactType
>
artifactTypes
=
<
ArtifactType
>[
ArtifactType
.
androidIcuData
,
ArtifactType
.
androidClasses
Dex
,
ArtifactType
.
androidClasses
Jar
,
ArtifactType
.
androidLibSkyShell
,
ArtifactType
.
androidKeystore
,
];
...
...
@@ -183,11 +241,13 @@ class ApkCommand extends FlutterCommand {
components
.
androidSdk
=
new
Directory
(
androidSdkPath
);
components
.
manifest
=
new
File
(
argResults
[
'manifest'
]);
components
.
icuData
=
new
File
(
artifactPaths
[
0
]);
components
.
classesDex
=
new
File
(
artifactPaths
[
1
])
;
components
.
jars
=
[
new
File
(
artifactPaths
[
1
])]
;
components
.
libSkyShell
=
new
File
(
artifactPaths
[
2
]);
components
.
debugKeystore
=
new
File
(
artifactPaths
[
3
]);
components
.
resources
=
new
Directory
(
argResults
[
'resources'
]);
await
_findServices
(
components
);
if
(!
components
.
resources
.
existsSync
())
{
// TODO(eseidel): This level should be higher when path is manually set.
logging
.
info
(
'Can not locate Resources:
${components.resources}
, ignoring.'
);
...
...
@@ -204,8 +264,9 @@ class ApkCommand extends FlutterCommand {
logging
.
severe
(
'and version
$_kBuildToolsVersion
of the build tools.'
);
return
null
;
}
for
(
File
f
in
[
components
.
manifest
,
components
.
icuData
,
components
.
classesDex
,
components
.
libSkyShell
,
components
.
debugKeystore
])
{
for
(
File
f
in
[
components
.
manifest
,
components
.
icuData
,
components
.
libSkyShell
,
components
.
debugKeystore
]
..
addAll
(
components
.
jars
))
{
if
(!
f
.
existsSync
())
{
logging
.
severe
(
'Can not locate file:
${f.path}
'
);
return
null
;
...
...
@@ -215,18 +276,44 @@ class ApkCommand extends FlutterCommand {
return
components
;
}
// Outputs a services.json file for the flutter engine to read. Format:
// {
// services: [
// { name: string, class: string },
// ...
// ]
// }
void
_generateServicesConfig
(
File
servicesConfig
,
List
<
Map
<
String
,
String
>>
servicesIn
)
{
List
<
Map
<
String
,
String
>>
services
=
servicesIn
.
map
((
Map
<
String
,
String
>
service
)
=>
{
'name'
:
service
[
'name'
],
'class'
:
service
[
'registration-class'
]
}).
toList
();
Map
<
String
,
dynamic
>
json
=
{
'services'
:
services
};
servicesConfig
.
writeAsStringSync
(
JSON
.
encode
(
json
),
mode:
FileMode
.
WRITE
,
flush:
true
);
}
int
_buildApk
(
_ApkComponents
components
,
String
flxPath
)
{
Directory
tempDir
=
Directory
.
systemTemp
.
createTempSync
(
'flutter_tools'
);
try
{
_ApkBuilder
builder
=
new
_ApkBuilder
(
components
.
androidSdk
.
path
);
File
classesDex
=
new
File
(
'
${tempDir.path}
/classes.dex'
);
builder
.
compileClassesDex
(
classesDex
,
components
.
jars
);
File
servicesConfig
=
new
File
(
'
${tempDir.path}
/services.json'
);
_generateServicesConfig
(
servicesConfig
,
components
.
services
);
_AssetBuilder
assetBuilder
=
new
_AssetBuilder
(
tempDir
,
'assets'
);
assetBuilder
.
add
(
components
.
icuData
,
'icudtl.dat'
);
assetBuilder
.
add
(
new
File
(
flxPath
),
'app.flx'
);
assetBuilder
.
add
(
servicesConfig
,
'services.json'
);
_AssetBuilder
artifactBuilder
=
new
_AssetBuilder
(
tempDir
,
'artifacts'
);
artifactBuilder
.
add
(
c
omponents
.
c
lassesDex
,
'classes.dex'
);
artifactBuilder
.
add
(
classesDex
,
'classes.dex'
);
artifactBuilder
.
add
(
components
.
libSkyShell
,
'lib/armeabi-v7a/libsky_shell.so'
);
_ApkBuilder
builder
=
new
_ApkBuilder
(
components
.
androidSdk
.
path
);
File
unalignedApk
=
new
File
(
'
${tempDir.path}
/app.apk.unaligned'
);
builder
.
package
(
unalignedApk
,
components
.
manifest
,
assetBuilder
.
directory
,
artifactBuilder
.
directory
,
components
.
resources
);
...
...
packages/gcm/lib/apk/config.yaml
0 → 100644
View file @
0f505fbf
services
:
-
name
:
gcm::GcmService
registration-class
:
org.domokit.gcm.RegistrationIntentService$MojoService
jars
:
-
android-sdk:extras/google/google_play_services/libproject/google-play-services_lib/libs/google-play-services.jar
-
android-sdk:extras/android/support/v13/android-support-v13.jar
-
android-sdk:extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar
-
android-sdk:extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar
-
https://storage.googleapis.com/mojo_infra/flutter/c03a5dda7e78c50d74fe5e5ed72eed1de6ae993d/android-arm/gcm/gcm_lib.dex.jar
-
https://storage.googleapis.com/mojo_infra/flutter/c03a5dda7e78c50d74fe5e5ed72eed1de6ae993d/android-arm/gcm/interfaces_java.dex.jar
todo
:
>
Maybe we should link to a URL to download the jars. Might need different
versions per platform, etc.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment