Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'android' for task ':react-native-vision-camera:jitsiAndroidSourcesJar' of type org.gradle.api.tasks.bundling.Jar. #1015

Closed
4 tasks done
praveenbalajia opened this issue Apr 24, 2022 · 4 comments · Fixed by #1466
Labels
🐛 bug Something isn't working

Comments

@praveenbalajia
Copy link

praveenbalajia commented Apr 24, 2022

What were you trying to do?

I wanted to show the camera preview on the Android platform and facing some build issue
on iOS it's working fine

Reproduceable Code

Install the Library adding manual installation step

include ':react-native-vision-camera'
project(':react-native-vision-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vision-camera/android')

in settings.gradle file

What happened instead?

The app is throwing build issues on Android studio Arctic fox

project info

buildToolsVersion = "30.0.3"
compileSdkVersion = 31
minSdkVersion    = 23
targetSdkVersion = 31
supportLibVersion = "28.0.0"
ndkVersion = "21.4.7075529"

classpath 'com.android.tools.build:gradle:4.2.2'

distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip

Relevant log output

Caused by: groovy.lang.MissingPropertyException: Cannot get property 'react' on extra properties extension as it does not exist

Caused by: groovy.lang.MissingPropertyException: Could not get unknown property 'android' for task ':react-native-vision-camera:jitsiAndroidSourcesJar' of type org.gradle.api.tasks.bundling.Jar.

Device

emulator

VisionCamera Version

2.13.1

Additional information

@praveenbalajia praveenbalajia added the 🐛 bug Something isn't working label Apr 24, 2022
@mrousavy
Copy link
Owner

Please share both of your build.gradle files.

@praveenbalajia
Copy link
Author

Compressed_build_files.zip
@mrousavy Please check ZIP i have shared both of them

@mrousavy
Copy link
Owner

Hey - I'm not downloading/opening .zip files from an untrusted source. Please share them via code snippets here (```).

Also, make sure to compare your files with the RN Template (https://github.com/facebook/react-native/blob/main/template/android/app/build.gradle) to make sure you didnt remove anything critical. From the error message it looks like something like project.ext.react = [ ... is missing in yours

@praveenbalajia
Copy link
Author

Project Gradle content

import groovy.json.JsonSlurper
import org.gradle.util.VersionNumber

// Top-level build file where you can add configuration options common to all
// sub-projects/modules.

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.2.2'
        classpath 'com.google.gms:google-services:4.3.10'
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
    }
}

ext {
    buildToolsVersion = "30.0.3"
    compileSdkVersion = 31
    minSdkVersion    = 23
    targetSdkVersion = 31
    supportLibVersion = "28.0.0"
    ndkVersion = "21.4.7075529"

    // The Maven artifact groupdId of the third-party react-native modules which
    // Jitsi Meet SDK for Android depends on and which are not available in
    // third-party Maven repositories so we have to deploy to a Maven repository
    // of ours.
    moduleGroupId = 'com.facebook.react'

    // Maven repo where artifacts will be published
    mavenRepo = System.env.MVN_REPO ?: ""
    mavenUser = System.env.MVN_USER ?: ""
    mavenPassword = System.env.MVN_PASSWORD ?: ""

    // Libre build
    libreBuild = (System.env.LIBRE_BUILD ?: "false").toBoolean()

    googleServicesEnabled = project.file('app/google-services.json').exists() && !libreBuild
}

allprojects {
    repositories {
        // React Native (JS, Obj-C sources, Android binaries) is installed from npm.
        maven { url "$rootDir/../node_modules/react-native/android" }
        // Android JSC is installed from npm.
        maven { url("$rootDir/../node_modules/jsc-android/dist") }
        mavenCentral {
            // We don't want to fetch react-native from Maven Central as there are
            // older versions over there.
            content {
                excludeGroup "com.facebook.react"
            }
        }
        google()
        maven { url 'https://www.jitpack.io' }
    }

    // Make sure we use the react-native version in node_modules and not the one
    // published in jcenter / elsewhere.
    configurations.all {
        resolutionStrategy {
            eachDependency { DependencyResolveDetails details ->
                if (details.requested.group == 'com.facebook.react'
                        && details.requested.name == 'react-native') {
                    def file = new File("$rootDir/../node_modules/react-native/package.json")
                    def version = new JsonSlurper().parseText(file.text).version
                    details.useVersion version
                }
            }
        }
    }

    // Third-party react-native modules which Jitsi Meet SDK for Android depends
    // on and which are not available in third-party Maven repositories need to
    // be deployed in a Maven repository of ours.
    //

    if (project.name.startsWith('react-native-')) {
        apply plugin: 'maven-publish'
        publishing {
            publications {}
            repositories {
                maven {
                    url rootProject.ext.mavenRepo
                    if (!rootProject.ext.mavenRepo.startsWith("file")) {
                        credentials {
                            username rootProject.ext.mavenUser
                            password rootProject.ext.mavenPassword
                        }
                    }
                }
            }
        }
    }

    // Use the number of seconds/10 since Jan 1 2019 as the version qualifier number.
    // This will last for the next ~680 years.
    // https://stackoverflow.com/a/38643838
    def versionQualifierNumber = (int)(((new Date().getTime()/1000) - 1546297200) / 10)

    afterEvaluate { project ->
        if (project.plugins.hasPlugin('android') || project.plugins.hasPlugin('android-library')) {
            project.android {
                compileSdkVersion rootProject.ext.compileSdkVersion
                buildToolsVersion rootProject.ext.buildToolsVersion
            }
        }

        if (project.name.startsWith('react-native-')) {
            def npmManifest = project.file('../package.json')
            def json = new JsonSlurper().parseText(npmManifest.text)

            // Release every dependency the SDK has with a -jitsi-XXX qualified version. This allows
            // us to pin the dependencies and make sure they are always updated, no matter what.

            project.version = "${json.version}-jitsi-${versionQualifierNumber}"

            task jitsiAndroidSourcesJar(type: Jar) {
                classifier = 'sources'
                from android.sourceSets.main.java.source
            }

            publishing.publications {
                aarArchive(MavenPublication) {
                    groupId rootProject.ext.moduleGroupId
                    artifactId project.name
                    version project.version

                    artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
                        extension "aar"
                    }
                    artifact(jitsiAndroidSourcesJar)
                    pom.withXml {
                        def pomXml = asNode()
                        pomXml.appendNode('name', project.name)
                        pomXml.appendNode('description', json.description)
                        pomXml.appendNode('url', json.homepage)
                        if (json.license) {
                            def license = pomXml.appendNode('licenses').appendNode('license')
                            license.appendNode('name', json.license)
                            license.appendNode('distribution', 'repo')
                        }

                        def dependencies = pomXml.appendNode('dependencies')
                        configurations.getByName('releaseCompileClasspath').getResolvedConfiguration().getFirstLevelModuleDependencies().each {
                            def artifactId = it.moduleName
                            def version = it.moduleVersion
                            // React Native signals breaking changes by
                            // increasing the minor version number. So the
                            // (third-party) React Native modules we utilize can
                            // depend not on a specific react-native release but
                            // a wider range.
                            if (artifactId == 'react-native') {
                                def versionNumber = VersionNumber.parse(version)
                                version = "${versionNumber.major}.${versionNumber.minor}"
                            }

                            def dependency = dependencies.appendNode('dependency')
                            dependency.appendNode('groupId', it.moduleGroup)
                            dependency.appendNode('artifactId', artifactId)
                            dependency.appendNode('version', version)
                        }
                    }
                }
            }
        }
    }
}

// Force the version of the Android build tools we have chosen on all
// subprojects. The forcing was introduced for react-native and the third-party
// modules that we utilize such as react-native-background-timer.
subprojects { subproject ->
    afterEvaluate{
        if ((subproject.plugins.hasPlugin('android')
                    || subproject.plugins.hasPlugin('android-library'))
                && rootProject.ext.has('buildToolsVersion')) {
            android {
                buildToolsVersion rootProject.ext.buildToolsVersion
            }
        }
    }
}

app/build.gradle

apply plugin: 'com.android.application'

// Crashlytics integration is done as part of Firebase now, so it gets
// automagically activated with google-services.json
if (googleServicesEnabled) {
    apply plugin: 'com.google.firebase.crashlytics'
}

// Use the number of seconds/10 since Jan 1 2019 as the versionCode.
// This lets us upload a new build at most every 10 seconds for the
// next ~680 years.
// https://stackoverflow.com/a/38643838
def vcode = (int) (((new Date().getTime() / 1000) - 1546297200) / 10)

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    packagingOptions {
        exclude 'lib/*/libhermes*.so'
    }

    defaultConfig {
        applicationId 'org.jitsi.meet'
        versionCode vcode
        versionName project.appVersion

        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion

        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }

    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }

    buildTypes {
        debug {
            buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
            buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
        }
        release {
            // Uncomment the following line for singing a test release build.
            //signingConfig signingConfigs.debug
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules-release.pro'
            buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${googleServicesEnabled}"
            buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
        }
    }

    sourceSets {
        main {
            java {
                if (rootProject.ext.libreBuild) {
                    srcDir "src"
                    exclude "**/GoogleServicesHelper.java"
                }
            }
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // https://github.com/facebook/react-native/issues/31572
    // We can update past 1.4.0 on RN 0.68
    implementation ('androidx.appcompat:appcompat:1.3.1') {
        version {
            strictly '1.3.1'
        }
    }

    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'

    if (!rootProject.ext.libreBuild) {
        implementation 'com.google.android.gms:play-services-auth:16.0.1'

        // Firebase
        //  - Crashlytics
        //  - Dynamic Links
        implementation 'com.google.firebase:firebase-analytics:17.5.0'
        implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
        implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
    }

    implementation project(':sdk')
}

gradle.projectsEvaluated {
    // Dropbox integration
    //

    def dropboxAppKey
    if (project.file('dropbox.key').exists()) {
        dropboxAppKey = project.file('dropbox.key').text.trim() - 'db-'
    }

    if (dropboxAppKey) {
        android.defaultConfig.resValue('string', 'dropbox_app_key', "${dropboxAppKey}")

        def dropboxActivity = """
          <activity
              android:configChanges="keyboard|orientation"
              android:exported="true"
              android:launchMode="singleTask"
              android:name="com.dropbox.core.android.AuthActivity">
            <intent-filter>
              <action android:name="android.intent.action.VIEW" />
              <category android:name="android.intent.category.BROWSABLE" />
              <category android:name="android.intent.category.DEFAULT" />
              <data android:scheme="db-${dropboxAppKey}" />
            </intent-filter>
          </activity>"""

        android.applicationVariants.all { variant ->
            variant.outputs.each { output ->
                output.getProcessManifestProvider().get().doLast {
                    def outputDir = multiApkManifestOutputDirectory.get().asFile
                    def manifestPath = new File(outputDir, 'AndroidManifest.xml')
                    def charset = 'UTF-8'
                    def text
                    text = manifestPath.getText(charset)
                    text = text.replace('</application>', "${dropboxActivity}</application>")
                    manifestPath.write(text, charset)
                }
            }
        }
    }

    // Run React packager
    android.applicationVariants.all { variant ->
        def targetName = variant.name.capitalize()

        def currentRunPackagerTask = tasks.create(
            name: "run${targetName}ReactPackager",
            type: Exec) {
            group = "react"
            description = "Run the React packager."

            doFirst {
                println "Starting the React packager..."

                def androidRoot = file("${projectDir}/../")

                // Set up the call to the script
                workingDir androidRoot

                // Run the packager
                commandLine("scripts/run-packager.sh")
            }

            // Set up dev mode
            def devEnabled = !targetName.toLowerCase().contains("release")

            // Only enable for dev builds
            enabled devEnabled
        }

        def packageTask = variant.packageApplicationProvider.get()

        packageTask.dependsOn(currentRunPackagerTask)
    }

}

if (googleServicesEnabled) {
    apply plugin: 'com.google.gms.google-services'
}

sdk/build.gradle

apply plugin: 'com.android.library'
apply plugin: 'maven-publish'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    ndkVersion rootProject.ext.ndkVersion

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
    }

    buildTypes {
        debug {
            buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
            buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            buildConfigField "boolean", "LIBRE_BUILD", "${rootProject.ext.libreBuild}"
            buildConfigField "boolean", "GOOGLE_SERVICES_ENABLED", "${rootProject.ext.googleServicesEnabled}"
        }
    }

    sourceSets {
        main {
            java {
                exclude "test/"
            }
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // https://github.com/facebook/react-native/issues/31572
    // We can update past 1.4.0 on RN 0.68
    implementation ('androidx.appcompat:appcompat:1.3.1') {
        version {
            strictly '1.3.1'
        }
    }
    implementation 'androidx.fragment:fragment:1.4.0'
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

    //noinspection GradleDynamicVersion
    api 'com.facebook.react:react-native:+'
    //noinspection GradleDynamicVersion
    implementation 'org.webkit:android-jsc:+'

    implementation 'com.facebook.fresco:animated-gif:2.5.0'
    implementation 'com.dropbox.core:dropbox-core-sdk:4.0.1'
    implementation 'com.jakewharton.timber:timber:4.7.1'
    implementation 'com.squareup.duktape:duktape-android:1.3.0'
    implementation 'com.google.code.gson:gson:2.8.6'
    implementation "androidx.startup:startup-runtime:1.1.0"

    if (rootProject.ext.libreBuild) {
        implementation(project(':react-native-device-info')) {
            exclude group: 'com.google.firebase'
            exclude group: 'com.google.android.gms'
            exclude group: 'com.android.installreferrer'
        }
    } else {
        implementation project(':react-native-amplitude')
        implementation project(':react-native-device-info')
        implementation(project(":react-native-google-signin")) {
            exclude group: 'com.google.android.gms'
            exclude group: 'androidx'
        }
    }

    implementation project(':react-native-async-storage')
    implementation project(':react-native-background-timer')
    implementation project(':react-native-calendar-events')
    implementation project(':react-native-community_clipboard')
    implementation project(':react-native-community_netinfo')
    implementation project(':react-native-default-preference')
    implementation project(':react-native-gesture-handler')
    implementation project(':react-native-get-random-values')
    implementation project(':react-native-giphy')
    implementation project(':react-native-immersive')
    implementation project(':react-native-keep-awake')
    implementation project(':react-native-masked-view_masked-view')
    implementation project(':react-native-pager-view')
    implementation project(':react-native-performance')
    implementation project(':react-native-reanimated')
    implementation project(':react-native-safe-area-context')
    implementation project(':react-native-screens')
    implementation project(':react-native-slider')
    implementation project(':react-native-sound')
    implementation project(':react-native-splash-screen')
    implementation project(':react-native-svg')
    implementation project(':react-native-video')
    implementation project(':react-native-webrtc')
    implementation project(':react-native-webview')
//    implementation project(':react-native-vision-camera')
    implementation "androidx.camera:camera-core:1.1.0-alpha08"

    testImplementation 'junit:junit:4.12'
}


// Here we bundle all assets, resources and React files. We cannot use the
// react.gradle file provided by react-native because it's designed to be used
// in an application (it taps into applicationVariants, but the SDK is a library
// so we need libraryVariants instead).
android.libraryVariants.all { def variant ->
    // Create variant and target names
    def targetName = variant.name.capitalize()
    def targetPath = variant.dirName

    // React js bundle directories
    def jsBundleDir = file("$buildDir/generated/assets/react/${targetPath}")
    def resourcesDir = file("$buildDir/generated/res/react/${targetPath}")

    def jsBundleFile = file("$jsBundleDir/index.android.bundle")

    def currentBundleTask = tasks.create(
            name: "bundle${targetName}JsAndAssets",
            type: Exec) {
        group = "react"
        description = "bundle JS and assets for ${targetName}."

        // Create dirs if they are not there (e.g. the "clean" task just ran)
        doFirst {
            jsBundleDir.deleteDir()
            jsBundleDir.mkdirs()
            resourcesDir.deleteDir()
            resourcesDir.mkdirs()
        }

        // Set up inputs and outputs so gradle can cache the result
        def reactRoot = file("${projectDir}/../../")
        inputs.files fileTree(dir: reactRoot, excludes: ["android/**", "ios/**"])
        outputs.dir jsBundleDir
        outputs.dir resourcesDir

        // Set up the call to the react-native cli
        workingDir reactRoot

        // Set up dev mode
        def devEnabled = !targetName.toLowerCase().contains("release")

        // Run the bundler
        commandLine(
                "node",
                "node_modules/react-native/local-cli/cli.js",
                "bundle",
                "--platform", "android",
                "--dev", "${devEnabled}",
                "--reset-cache",
                "--entry-file", "index.android.js",
                "--bundle-output", jsBundleFile,
                "--assets-dest", resourcesDir)

        // Disable bundling on dev builds
        enabled !devEnabled
    }

    currentBundleTask.ext.generatedResFolders = files(resourcesDir).builtBy(currentBundleTask)
    currentBundleTask.ext.generatedAssetsFolders = files(jsBundleDir).builtBy(currentBundleTask)
    variant.registerGeneratedResFolders(currentBundleTask.generatedResFolders)

    def mergeAssetsTask = variant.mergeAssetsProvider.get()
    def mergeResourcesTask = variant.mergeResourcesProvider.get()

    mergeAssetsTask.dependsOn(currentBundleTask)
    mergeResourcesTask.dependsOn(currentBundleTask)

    mergeAssetsTask.doLast {
        def assetsDir = mergeAssetsTask.outputDir.get()

        // Bundle sounds
        //
        copy {
            from("${projectDir}/../../sounds")
            include("*.wav")
            include("*.mp3")
            into("${assetsDir}/sounds")
        }

        // Copy React assets
        //
        if (currentBundleTask.enabled) {
            copy {
                from(jsBundleFile)
                into(assetsDir)
            }
        }
    }

    mergeResourcesTask.doLast {
        // Copy React resources
        //
        if (currentBundleTask.enabled) {
            copy {
                from(resourcesDir)
                into(mergeResourcesTask.outputDir.get())
            }
        }
    }
}


publishing {
    publications {
        aarArchive(MavenPublication) {
            groupId 'org.jitsi.react'
            artifactId 'jitsi-meet-sdk'
            version System.env.OVERRIDE_SDK_VERSION ?: project.sdkVersion

            artifact("${project.buildDir}/outputs/aar/${project.name}-release.aar") {
                extension "aar"
            }
            pom.withXml {
                def pomXml = asNode()
                pomXml.appendNode('name', 'jitsi-meet-sdk')
                pomXml.appendNode('description', 'Jitsi Meet SDK for Android')
                def dependencies = pomXml.appendNode('dependencies')
                configurations.getByName('releaseCompileClasspath').getResolvedConfiguration().getFirstLevelModuleDependencies().each {
                    // The (third-party) React Native modules that we depend on
                    // are in source code form and do not have groupId. That is
                    // why we have a dedicated groupId for them. But the other
                    // dependencies come through Maven and, consequently, have
                    // groupId.
                    def groupId = it.moduleGroup
                    def artifactId = it.moduleName

                    if (artifactId.startsWith('react-native-')) {
                        groupId = rootProject.ext.moduleGroupId
                    }

                    def dependency = dependencies.appendNode('dependency')
                    dependency.appendNode('groupId', groupId)
                    dependency.appendNode('artifactId', artifactId)
                    dependency.appendNode('version', it.moduleVersion)
                }
            }
        }

    }
    repositories {
        maven {
            url rootProject.ext.mavenRepo
            if (!rootProject.ext.mavenRepo.startsWith("file")) {
                credentials {
                    username rootProject.ext.mavenUser
                    password rootProject.ext.mavenPassword
                }
            }
        }
    }
}

To Mention this is jitsi project am doing a customization
https://github.com/jitsi/jitsi-meet

mrousavy added a commit that referenced this issue Sep 1, 2023
See #1376

## Breaking Changes

* Frame Processors are now **synchronous**. Previously they ran on a
separate Thread. If you want to run something on a separate Thread now,
use `runAsync` inside a Frame Processor
* Frame Processor Plugins are no longer in the global object with the
`__` prefix, but rather stored directly in the `FrameProcessorPlugins`
object exported by react-native-vision-camera. (e.g. replace
`__scanQRCodes(frame)` with `FrameProcessorPlugins.scanQRCodes(frame)`)
* `frameProcessorFps` no longer exists. Use `runAtTargetFps` inside a
Frame Processor to throttle some calls.
* `onFrameProcessorPerformanceSuggestionAvailable` no longer exists. Use
the FPS display (`enableFpsGraph={true}`) to see how your Frame
Processor performs over time. This is more in-line with how React Native
works (Dev Tools / Perf Monitor)
* VisionCamera V3 will not work on RN 0.70 or below. You need to use RN
0.71. This is because the build script got way simpler and smaller,
making it faster to build and way less error prone. Backwards
compatibility is just too complex here.
* Reanimated is no longer used as a Worklet Runtime. Instead,
VisionCamera now uses
[react-native-worklets-core](https://github.com/margelo/react-native-worklets-core).

## Progress

You can test the latest V3 release by creating a new RN project with RN
0.71 and installing VisionCamera + RNWorklets:

```sh
yarn add react-native-vision-camera@3.0.0-rc.5
yarn add react-native-worklets-core
yarn add @shopify/react-native-skia
```

Things to test:

* TensorFlow Lite plugin to load any `.tflite` model!! ✨ (see [this PR
for more
info](#1633),
will be a separate library soon)
* Drawing onto a Frame using Skia!! 🎉 
* Using `frame.toArrayBuffer()` to get the Frame's byte content in JS
* New Android build script. This should drastically speed up the build
time! 💨
* New Worklet library. This replaces Reanimated Worklets. Should be
faster and more stable :)
* New synchronous Frame Processors. Should be faster :)
* `runAtTargetFps` and `runAsync` in Frame Processors
* Using HostObjects or HostFunctions (like models from PyTorch) inside a
Frame Processor. This will probably require a few native bindings on
PyTorch's end to make the integration work (cc @raedle)

Overall V3 is close to completion. I have a few things to do the coming
days so not sure how much work I can put into this. **If anyone wants to
support the development of v3, I'd appreciate donations / sponsors:
https://github.com/sponsors/mrousavy** ❤️ :)


## Related issues 

features

- resolves
#1376
- fixes
#281
- resolves
#211
- resolves
#130
- resolves
#117
- fixes #76
- resolves
#75
- resolves
#562
- resolves
#565
- fixes
#570
- fixes
#287
- resolves
#311
- fixes
#315
- resolves
#323
- fixes
#340
- fixes
#354
- resolves
#420
- fixes
#434
- fixes
#452
- fixes
#496
- fixes
#497
- resolves
#499
- fixes
#516
- fixes
#527
- fixes
#542
- fixes
#548
- fixes
#561
- fixes
#740
- fixes
#770


...and then pretty much every Android issue lol

- fixes
#1675
(**maybe**, please test @PrernaBudhraja)
- fixes
#1671

.. maybe also (not tested):

- fixes
#1698
- fixes
#1687
- fixes
#1685
- fixes
#1681
- fixes
#1650
- fixes
#1646
- fixes
#1635
- fixes
#1631
- fixes
#1621
- fixes
#1615
- fixes
#1612
- fixes
#1605
- fixes
#1599
- fixes
#1585
- fixes
#1581
- fixes
#1569
- fixes
#1568
- fixes
#1565
- fixes
#1561
- fixes
#1558
- fixes
#1554
- fixes
#1551
- fixes
#1547
- fixes
#1543
- fixes
#1538
- fixes
#1536
- fixes
#1534
- fixes
#1528
- fixes
#1520
- fixes
#1498
- fixes
#1489
- fixes
#1477
- fixes
#1474
- fixes
#1463
- fixes
#1462
- fixes
#1449
- fixes
#1443
- fixes
#1437
- fixes
#1431
- fixes
#1429
- fixes
#1427
- fixes
#1423
- fixes
#1416
- fixes
#1407
- fixes
#1403
- fixes
#1402
- fixes
#1398
- fixes
#1396
- fixes
#1395
- fixes
#1379
- fixes
#1377
- fixes
#1374
- fixes
#1373
- fixes
#1365
- fixes
#1356
- fixes
#1353
- fixes
#1352
- fixes
#1351
- fixes
#1343
- fixes
#1340
- fixes
#1334
- fixes
#1330
- fixes
#1322
- fixes
#1296
- fixes
#1283
- fixes
#1260
- fixes
#1253
- fixes
#1251
- fixes
#1245
- fixes
#1238
- fixes
#1227
- fixes
#1226
- fixes
#1225
- fixes
#1222
- fixes
#1211
- fixes
#1208
- fixes
#1193
- fixes
#1191
- fixes
#1184
- fixes
#1164
- fixes
#1143
- fixes
#1128
- fixes
#1122
- fixes
#1120
- fixes
#1110
- fixes
#1097
- fixes
#1081
- fixes
#1080
- fixes
#1064
- fixes
#1053
- fixes
#1047
- fixes
#1044
- fixes
#1032
- fixes
#1026
- fixes
#1023
- fixes
#1015
- fixes
#1012
- fixes
#997
- fixes
#960
- fixes
#959
- fixes
#954
- fixes
#946
- fixes
#945
- fixes
#922
- fixes
#908
- fixes
#907
- fixes
#868
- fixes
#855
- fixes
#834
- fixes
#793
- fixes
#779
- fixes
#746
- fixes
#740
- fixes
#727
- fixes
#671
- fixes
#613
- fixes
#595
- fixes
#588
- fixes
#570
- fixes
#569
- fixes
#542
- fixes
#516
- fixes
#515
- fixes
#434
- fixes
#354
- fixes
#323
- fixes
#315
- fixes
#281
- fixes
#211
- fixes #76
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants