Add render tests to Gradle project root at platform/android (#2162)
This commit is contained in:
@@ -1,12 +1,65 @@
|
||||
# Developing - MapLibre Native for Android
|
||||
|
||||
These instructions are for developers interested in making code-level contributions to the SDK itself.
|
||||
These instructions are for developers interested in making code-level contributions to MapLibre Native for Android.
|
||||
|
||||
## Getting the source
|
||||
|
||||
Clone the git repository and pull in submodules:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:maplibre/maplibre-native.git
|
||||
cd maplibre-native
|
||||
git submodule update --init --recursive
|
||||
cd platform/android
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
[Android Studio](https://developer.android.com/studio) needs to be installed.
|
||||
|
||||
Open the `platform/android` directory to get started.
|
||||
|
||||
## Setting an API Key
|
||||
|
||||
_The test application (used for development purposes) uses MapTiler vector tiles, which require a MapTiler account and API key._
|
||||
|
||||
With the first Gradle invocation, Gradle will take the value of the `MLN_API_KEY` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml`. If the environment variable wasn't set, you can edit `developer-config.xml` manually and add your API key to the `api_key` resource.
|
||||
|
||||
## Running the TestApp
|
||||
|
||||
Run the configuration for the `MapboxGLAndroidSDKTestApp` module and select a device or emulator to deploy on.
|
||||
|
||||
<p align="left">
|
||||
<img src="https://github.com/maplibre/maplibre-native/assets/649392/5494925e-8cbb-4d5d-8033-8a2f141ede3c" alt="Android TestApp menu" width="15%"> <img src="https://github.com/maplibre/maplibre-native/assets/649392/f169db51-615d-4fca-b297-ac6197bec674" alt="Android TestApp showing Demotiles" width="15%">
|
||||
</p>
|
||||
|
||||
## Render Tests
|
||||
|
||||
To run the render tests for Android, run the configuration for the `androidRenderTest.app` module.
|
||||
|
||||
## Instrumentation Tests
|
||||
|
||||
To run the instrumentatin tests, find the `MapboxGLAndroidSDKTestApp` project in the sidebar, go to `src > androidTest`, right click and select "Run 'All Tests'".
|
||||
|
||||
<img width="246" alt="image" src="https://github.com/maplibre/maplibre-native/assets/649392/d9daf630-cb7f-4035-b426-fc496081fed9">
|
||||
|
||||
Your device needs remain unlocked for the duration of the tests.
|
||||
|
||||
The instrumentation tests take a long time to run (depending on the device, about an hour). You can modify the run configuration in Android Studio and add the regex `^(?!.*org\.maplibre\.android\.benchmark).*$` to exclude the benchmark.
|
||||
|
||||
### AWS Device Farm
|
||||
|
||||
The instrumentation tests are running on AWS Device Farm. To see the results and the logs, go to:
|
||||
|
||||
https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-east-1#/mobile/projects/20687d72-0e46-403e-8f03-0941850665bc/runs
|
||||
|
||||
You can log with the `maplibre` alias, with `maplibre` as username and `maplibre` as password (this is a read-only account).
|
||||
|
||||
## Kotlin
|
||||
|
||||
All new code should be written in [Kotlin](https://kotlinlang.org/).
|
||||
|
||||
### Style Checking
|
||||
## Style Checking
|
||||
|
||||
To check Kotlin style, we use [ktlint](https://pinterest.github.io/ktlint/). This linter is based on the [official Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html). We intergrate with it using the [kotlinder](https://github.com/jeremymailen/kotlinter-gradle) Gradle plugin.
|
||||
|
||||
@@ -20,114 +73,4 @@ To format all Kotlin source files, use:
|
||||
|
||||
```
|
||||
$ ./gradlew formatKotlin
|
||||
```
|
||||
|
||||
## Getting the source
|
||||
|
||||
Clone the git repository and pull in submodules:
|
||||
|
||||
```bash
|
||||
git clone git@github.com:maplibre/maplibre-native.git
|
||||
cd maplibre-native
|
||||
git submodule update --init --recursive
|
||||
cd platform/android
|
||||
```
|
||||
|
||||
## Installing dependencies
|
||||
|
||||
These dependencies are required for all operating systems and all platform targets.
|
||||
|
||||
- Latest stable [Android Studio](https://developer.android.com/studio/index.html)
|
||||
- Update the Mapbox Maps SDK for Android with the latest
|
||||
- Android SDK Build-Tools
|
||||
- Android Platform-Tools
|
||||
- Android SDK Tools
|
||||
- CMake
|
||||
- NDK
|
||||
- LLDB
|
||||
- Modern C++ compiler that supports `-std=c++14`\*
|
||||
- clang++ 3.5 or later or
|
||||
- g++-4.9 or later
|
||||
- [Node.js](https://nodejs.org/)
|
||||
- make sure [npm](https://www.npmjs.com) is installed as well
|
||||
- [ccache](https://ccache.samba.org/) (optional)
|
||||
|
||||
**Note**: We partially support C++14 because GCC 4.9 does not fully implement the
|
||||
final draft of the C++14 standard. More information in [DEVELOPING.md](../../DEVELOPING.md).
|
||||
|
||||
**Note**: On macOS you can install clang with installing the [Apple command line developer tools](https://developer.apple.com/download/).
|
||||
|
||||
## Opening the project
|
||||
|
||||
### macOS
|
||||
|
||||
* Environment
|
||||
* Android Studio
|
||||
* node
|
||||
* `JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home"`
|
||||
* `ANDROID_SDK_ROOT=~/Library/Android/sdk`
|
||||
* In Android Studio, go to Tools > [SDK Manager](https://developer.android.com/studio/projects/install-ndk#specific-version) to install CMake and the specific NDK version specified in [`dependencies.gradle`](https://github.com/maplibre/maplibre-native/blob/main/platform/android/gradle/dependencies.gradle).
|
||||
|
||||
Open `platform/android` with Android Studio.
|
||||
|
||||
### Linux
|
||||
|
||||
run `make android-configuration` in the root folder of the project and open in Android Studio.
|
||||
|
||||
If you are using Arch Linux, install [ncurses5-compat-libs](https://aur.archlinux.org/packages/ncurses5-compat-libs).
|
||||
|
||||
## Project configuration
|
||||
|
||||
### Setup Checkstyle
|
||||
|
||||
Mapbox uses specific IDE settings related to code and check style.
|
||||
See [checkstyle guide](https://github.com/mapbox/mapbox-gl-native-android/wiki/Setting-up-Mapbox-checkstyle) for configuration details.
|
||||
|
||||
#### Resolving duplicate file entries
|
||||
With buck build support, Android Studio can complain about duplicate source files. To remove this warning, open `MapboxGLAndroidSDK.iml` find the list of `excludeFolder` entries and add `<excludeFolder url="file://$MODULE_DIR$/../../../misc/" />` line.
|
||||
|
||||
### Setting API Key
|
||||
|
||||
_The test application (used for development purposes) uses MapTiler vector tiles, which require a MapTiler account and API key._
|
||||
|
||||
With the first gradle invocation, gradle will take the value of the `MLN_API_KEY` environment variable and save it to `MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml`. If the environment variable wasn't set, you can edit `developer-config.xml` manually and add your api key to the `api_key` resource.
|
||||
|
||||
## Running project
|
||||
|
||||
Run the configuration for the `MapboxGLAndroidSDKTestApp` module and select a device or emulator to deploy on. Based on the selected device, the c++ code will be compiled for the related processor architecture. You can see the project compiling in the `View > Tool Windows > Gradle Console`.
|
||||
|
||||
More information about building and distributing this project in [DISTRIBUTE.md](DISTRIBUTE.md).
|
||||
|
||||
## Additional resources
|
||||
|
||||
### Using the SDK snapshot
|
||||
|
||||
Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number:
|
||||
|
||||
```java
|
||||
// Mapbox SDK dependency
|
||||
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.1.0-SNAPSHOT'
|
||||
```
|
||||
|
||||
You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies:
|
||||
```
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/' }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Symbolicating native crashes
|
||||
|
||||
When hitting native crashes you can use ndk-stack to symbolicate crashes.
|
||||
More information in [this](https://github.com/mapbox/mapbox-gl-native-android/wiki/Getting-line-numbers-from-an-Android-crash-with-ndk-stack) guide.
|
||||
|
||||
## Instrumentation Tests
|
||||
|
||||
The results of the instrumentation tests can be accessed on the AWS Console:
|
||||
|
||||
https://us-west-2.console.aws.amazon.com/devicefarm/home?region=us-east-1#/mobile/projects/20687d72-0e46-403e-8f03-0941850665bc/runs
|
||||
|
||||
You can log with the `maplibre` alias, with `maplibre` as username and `maplibre` as password (this is a read-only account).
|
||||
```
|
||||
@@ -234,7 +234,7 @@ run-android-test-app-center:
|
||||
# Uploads the compiled Android SDK to Maven Central Staging
|
||||
.PHONY: run-android-publish
|
||||
run-android-publish:
|
||||
$(MLN_ANDROID_GRADLE_SINGLE_JOB) --debug -Pmapbox.abis=all :MapboxGLAndroidSDK:publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository
|
||||
$(MLN_ANDROID_GRADLE_SINGLE_JOB)-Pmapbox.abis=all :MapboxGLAndroidSDK:publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository
|
||||
|
||||
# Dump system graphics information for the test app
|
||||
.PHONY: android-gfxinfo
|
||||
|
||||
@@ -21,11 +21,7 @@ import java.nio.channels.FileChannel
|
||||
/**
|
||||
* The offline manager is the main entry point for offline-related functionality.
|
||||
*
|
||||
*
|
||||
* It'll help you list and create offline regions.
|
||||
*
|
||||
*
|
||||
* @see [Offline Maps Information/](https://docs.mapbox.com/help/troubleshooting/mobile-offline/)
|
||||
*/
|
||||
@UiThread
|
||||
class OfflineManager private constructor(context: Context) {
|
||||
@@ -106,9 +102,6 @@ class OfflineManager private constructor(context: Context) {
|
||||
fun onError(error: String)
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
init {
|
||||
this.context = context.applicationContext
|
||||
fileSource = FileSource.getInstance(this.context)
|
||||
@@ -126,11 +119,9 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Retrieve all regions in the offline database.
|
||||
*
|
||||
*
|
||||
* The query will be executed asynchronously and the results passed to the given
|
||||
* callback on the main thread.
|
||||
*
|
||||
*
|
||||
* @param callback the callback to be invoked
|
||||
*/
|
||||
fun listOfflineRegions(callback: ListOfflineRegionsCallback) {
|
||||
@@ -158,26 +149,21 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Merge offline regions from a secondary database into the main offline database.
|
||||
*
|
||||
*
|
||||
* When the merge is completed, or fails, the [MergeOfflineRegionsCallback] will be invoked on the main thread.
|
||||
* The callback reference is **strongly kept** throughout the process,
|
||||
* so it needs to be wrapped in a weak reference or released on the client side if necessary.
|
||||
*
|
||||
*
|
||||
* The secondary database may need to be upgraded to the latest schema.
|
||||
* This is done in-place and requires write-access to the provided path.
|
||||
* If the app's process doesn't have write-access to the provided path,
|
||||
* the file will be copied to the temporary, internal directory for the duration of the merge.
|
||||
*
|
||||
*
|
||||
* Only resources and tiles that belong to a region will be copied over. Identical
|
||||
* regions will be flattened into a single new region in the main database.
|
||||
*
|
||||
*
|
||||
* The operation will be aborted and [MergeOfflineRegionsCallback.onError] with an appropriate message
|
||||
* will be invoked if the merge would result in the offline tile count limit being exceeded.
|
||||
*
|
||||
*
|
||||
* Merged regions may not be in a completed status if the secondary database
|
||||
* does not contain all the tiles or resources required by the region definition.
|
||||
*
|
||||
@@ -218,12 +204,10 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Delete existing database and re-initialize.
|
||||
*
|
||||
*
|
||||
* When the operation is complete or encounters an error, the given callback will be
|
||||
* executed on the database thread; it is the responsibility of the SDK bindings
|
||||
* executed on the database thread; it is the responsibility of the platform bindings
|
||||
* to re-execute a user-provided callback on the main thread.
|
||||
*
|
||||
*
|
||||
* @param callback the callback to be invoked when the database was reset or when the operation erred.
|
||||
*/
|
||||
fun resetDatabase(callback: FileSourceCallback?) {
|
||||
@@ -248,17 +232,13 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Packs the existing database file into a minimal amount of disk space.
|
||||
*
|
||||
*
|
||||
* This operation has a performance impact as it will vacuum the database,
|
||||
* forcing it to move pages on the filesystem.
|
||||
*
|
||||
*
|
||||
*
|
||||
* When the operation is complete or encounters an error, the given callback will be
|
||||
* executed on the database thread; it is the responsibility of the SDK bindings
|
||||
* to re-execute a user-provided callback on the main thread.
|
||||
*
|
||||
*
|
||||
* @param callback the callback to be invoked when the database was reset or when the operation erred.
|
||||
*/
|
||||
fun packDatabase(callback: FileSourceCallback?) {
|
||||
@@ -283,18 +263,15 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Forces re-validation of the ambient cache.
|
||||
*
|
||||
*
|
||||
* Forces MapLibre GL Native to revalidate resources stored in the ambient
|
||||
* Forces MapLibre Native to revalidate resources stored in the ambient
|
||||
* cache with the tile server before using them, making sure they
|
||||
* are the latest version. This is more efficient than cleaning the
|
||||
* cache because if the resource is considered valid after the server
|
||||
* lookup, it will not get downloaded again.
|
||||
*
|
||||
*
|
||||
* Resources overlapping with offline regions will not be affected
|
||||
* by this call.
|
||||
*
|
||||
*
|
||||
* @param callback the callback to be invoked when the ambient cache was invalidated or when the operation erred.
|
||||
*/
|
||||
fun invalidateAmbientCache(callback: FileSourceCallback?) {
|
||||
@@ -319,13 +296,10 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Erase resources from the ambient cache, freeing storage space.
|
||||
*
|
||||
*
|
||||
* Erases the ambient cache, freeing resources.
|
||||
* Note that this operation can be potentially slow if packing the database
|
||||
* occurs automatically ([OfflineManager.runPackDatabaseAutomatically]).
|
||||
*
|
||||
*
|
||||
*
|
||||
* Resources overlapping with offline regions will not be affected
|
||||
* by this call.
|
||||
*
|
||||
@@ -354,7 +328,6 @@ class OfflineManager private constructor(context: Context) {
|
||||
/**
|
||||
* Sets the maximum size in bytes for the ambient cache.
|
||||
*
|
||||
*
|
||||
* This call is potentially expensive because it will try
|
||||
* to trim the data in case the database is larger than the
|
||||
* size defined. The size of offline regions are not affected
|
||||
@@ -362,25 +335,17 @@ class OfflineManager private constructor(context: Context) {
|
||||
* to not exceed the maximum size defined, taking into account
|
||||
* the current size for the offline regions.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Note that if you use the SDK's offline functionality, your ability to set the ambient cache size will be limited.
|
||||
* Space that offline regions take up detract from the space available for ambient caching, and the ambient cache
|
||||
* size does not block offline downloads. For example: if the maximum cache size is set to 50 MB and 40 MB are
|
||||
* already used by offline regions, the ambient cache size will effectively be 10 MB.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Setting the size to 0 will disable the cache if there is no
|
||||
* offline region on the database.
|
||||
*
|
||||
* <[
|
||||
*
|
||||
*
|
||||
* This method should always be called at the start of an app, before setting the style and loading a map.
|
||||
* Otherwise, the map will instantiate with the default cache size of 50 MB.
|
||||
*
|
||||
*
|
||||
* @param size the maximum size of the ambient cache
|
||||
* @param callback the callback to be invoked when the the maximum size has been set or when the operation erred.
|
||||
*/
|
||||
@@ -458,23 +423,13 @@ class OfflineManager private constructor(context: Context) {
|
||||
* Creates an offline region in the database by downloading the resources needed to use
|
||||
* the given region offline.
|
||||
*
|
||||
*
|
||||
* As of version 8.3.0 of the Maps SDK for Android, offline tile requests are no longer exempt from
|
||||
* billing on mobile. Developers are subject to separate Vector Tile or Raster Tile API pricing for
|
||||
* offline use. See [our pricing page](https://www.mapbox.com/pricing/) for more information.
|
||||
*
|
||||
*
|
||||
*
|
||||
* When the initial database queries have completed, the provided callback will be
|
||||
* executed on the main thread.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Note that the resulting region will be in an inactive download state; to begin
|
||||
* downloading resources, call `OfflineRegion.setDownloadState(DownloadState.STATE_ACTIVE)`,
|
||||
* optionally registering an `OfflineRegionObserver` beforehand.
|
||||
*
|
||||
*
|
||||
* @param definition the offline region definition
|
||||
* @param metadata the metadata in bytes
|
||||
* @param callback the callback to be invoked
|
||||
@@ -521,15 +476,13 @@ class OfflineManager private constructor(context: Context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of MapLibre-hosted tiles that may be downloaded and stored on the current device.
|
||||
* Sets the maximum number of tiles that may be downloaded and stored on the current device.
|
||||
* By default, the limit is set to 6,000.
|
||||
*
|
||||
*
|
||||
* Once this limit is reached, [OfflineRegion.OfflineRegionObserver.mapboxTileCountLimitExceeded]
|
||||
* fires every additional attempt to download additional tiles until already downloaded tiles are removed
|
||||
* by calling [OfflineRegion.delete].
|
||||
*
|
||||
*
|
||||
* @param limit the maximum number of tiles allowed to be downloaded
|
||||
*/
|
||||
@Keep
|
||||
@@ -539,7 +492,6 @@ class OfflineManager private constructor(context: Context) {
|
||||
* Sets whether database file packing occurs automatically.
|
||||
* By default, the automatic database file packing is enabled.
|
||||
*
|
||||
*
|
||||
* If packing is enabled, database file packing occurs automatically
|
||||
* after an offline region is deleted by calling
|
||||
* [OfflineRegion.delete]
|
||||
@@ -548,7 +500,6 @@ class OfflineManager private constructor(context: Context) {
|
||||
* If packing is disabled, disk space will not be freed after
|
||||
* resources are removed unless [OfflineManager.packDatabase] is explicitly called.
|
||||
*
|
||||
*
|
||||
* @param autopack flag setting the automatic database file packing.
|
||||
*/
|
||||
|
||||
@@ -593,7 +544,6 @@ class OfflineManager private constructor(context: Context) {
|
||||
* Use this method to pre-warm the cache with resources you know
|
||||
* will be requested.
|
||||
*
|
||||
*
|
||||
* This call is asynchronous: the data may not be immediately available
|
||||
* for in-progress requests, although subsequent requests should have
|
||||
* access to the cached data.
|
||||
|
||||
@@ -187,7 +187,7 @@ class MapGestureDetectorTest : BaseTest() {
|
||||
onView(withId(R.id.mapView)).perform(quickScale(-300f, withVelocity = false, duration = 750L))
|
||||
|
||||
rule.runOnUiThread {
|
||||
Assert.assertEquals(3.0, maplibreMap.cameraPosition.zoom, 0.0001)
|
||||
Assert.assertEquals(3.0, maplibreMap.cameraPosition.zoom, 0.001)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">MapLibre Android SDK TestApp</string>
|
||||
<string name="app_name">MapLibre Native Android TestApp</string>
|
||||
<string name="fps30">fps30</string>
|
||||
<string name="fps60">fps60</string>
|
||||
<string name="this_is_an_empty_fragment">This is an empty Fragment</string>
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
ext["signing.keyId"] = ''
|
||||
ext["signing.password"] = ''
|
||||
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
|
||||
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
|
||||
ext["signing.secretKeyRingFile"] = "${projectDir}/../signing-key.gpg"
|
||||
ext["ossrhUsername"] = ''
|
||||
ext["ossrhPassword"] = ''
|
||||
ext["sonatypeStagingProfileId"] = ''
|
||||
|
||||
File secretPropsFile = project.rootProject.file('local.properties')
|
||||
if (secretPropsFile.exists()) {
|
||||
// Read local.properties file first if it exists
|
||||
Properties p = new Properties()
|
||||
new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
|
||||
p.each { name, value -> ext[name] = value }
|
||||
} else {
|
||||
// Use system environment variables
|
||||
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
|
||||
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
|
||||
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
|
||||
ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
|
||||
ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
|
||||
}
|
||||
ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
|
||||
ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
|
||||
ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
include ':MapboxGLAndroidSDK', ':MapboxGLAndroidSDKTestApp', ':MapboxGLAndroidSDKLint'
|
||||
include ':MapboxGLAndroidSDK', ':MapboxGLAndroidSDKTestApp', ':MapboxGLAndroidSDKLint'
|
||||
|
||||
def renderTestProjectDir = new File(rootDir, '../../render-test/android')
|
||||
includeBuild(renderTestProjectDir)
|
||||
@@ -12,7 +12,7 @@ android {
|
||||
abi = project.getProperty('mapbox.abis')
|
||||
}
|
||||
ndk {
|
||||
if (abi != 'all') {
|
||||
if (abi != 'all' && abi != 'none') {
|
||||
abiFilters abi.split(' ')
|
||||
} else {
|
||||
abiFilters 'armeabi-v7a', 'x86', 'arm64-v8a', 'x86_64'
|
||||
|
||||
@@ -4,7 +4,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.0.2'
|
||||
classpath 'com.android.tools.build:gradle:8.1.4'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
include ':app'
|
||||
rootProject.name = "androidRenderTest"
|
||||
|
||||
include ":app"
|
||||
Reference in New Issue
Block a user