Unable to archive Kotlin Native with Cocoapods in XCode - xcode

I try to archive in XCode 12 a project referencing a Kotlin Native framework with cocoapods plugin, but it fails with message like this (using iPhone SE to build archive)
Ignoring file *MyFramework*, building for iOS-armv7 but attempting to link with file built for iOS-arm64
Undefined symbol: _OBJC_CLASS_$_... (for armv7)
I reference my framework in Podfile of the project as a local pod (using :path and :modular_headers => true)
As I understand I have to build a fat framework to include both armv7 and arm64 but how do I manage this using Kotlin cocoapods plugin?
Here are some links with recommendations, but I was unable to put it together in my case
https://github.com/ilmat192/kotlin-native-gradle-samples/blob/master/fat-framework/build.gradle.kts
https://github.com/JetBrains/kotlin-native/issues/3140
https://medium.com/#yuyaHorita/universal-frameworks-xcframework-with-kotlinnative-999d830e206e
https://github.com/JetBrains/kotlin-native/issues/2574
https://github.com/ilmat192/kotlin-native-gradle-samples/blob/master/fat-framework/build.gradle.kts
Project's build.gradle
buildscript {
ext.kotlinVersion = '1.4.20-M2'
// use 1.3.7 to avoid iOS build error
// "Deserializer for declaration public kotlinx.coroutines/SingleThreadDispatcher|null[0] is not found"
ext.coroutinesVersion = '1.3.7'
ext.ktorVersion = '1.4.1'
ext.napierVersion = '1.4.0'
repositories {
google()
jcenter()
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
}
}
repositories {
google()
jcenter()
}
Molule's build.gradle
plugins {
id 'org.jetbrains.kotlin.multiplatform' version "$kotlinVersion"
id "org.jetbrains.kotlin.native.cocoapods" version "$kotlinVersion"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlinVersion"
}
repositories {
google()
jcenter()
mavenCentral()
maven { url "https://dl.bintray.com/aakira/maven" }
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId 'org.jetbrains.kotlin.mpp_app_android'
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName '1.0'
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
}
buildTypes {
release {
minifyEnabled false
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
}
kotlin {
android("android")
targets {
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
? presets.iosArm64 : presets.iosX64
// https://kotlinlang.org/docs/reference/mpp-dsl-reference.html#native-targets
fromPreset(iOSTarget, 'ios') {
binaries {
}
}
}
// CocoaPods requires the podspec to have a version.
version = "1.0"
cocoapods {
// Configure fields required by CocoaPods.
def projectName = project.getRootProject().getName()
summary = projectName
homepage = "https://ya.ru"
ios.deploymentTarget = "9.0"
frameworkName = projectName
pod("NVHTarGzip")
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.9.1")
// Coroutines components
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
// workaround https://youtrack.jetbrains.com/issue/KT-41378
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt-2")
// Ktor components
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-network:$ktorVersion")
// workaround https://github.com/AAkira/Napier/issues/48
implementation "com.github.aakira:napier:1.4.1-alpha1"
}
}
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
androidMain {
dependencies {
// Ktor components
implementation("io.ktor:ktor-client-android:$ktorVersion")
}
}
androidTest {
dependencies {
implementation kotlin('test')
implementation kotlin('test-junit')
}
}
iosMain {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.9.1")
// Ktor components
implementation("io.ktor:ktor-client-ios:$ktorVersion")
}
}
iosTest {
}
}
}
Solution
Actually not a true solution - based on accepted answer I just dropped armv7 support adding it to Excluded Architectures

building for iOS-armv7 but attempting to link with file built for iOS-arm64
Looks like you're trying to archive for armv7, which (I think) is 32 bit ios, or maybe watch, etc. Most apps need just arm64, and your Xcode framework will only be arm64 according to this:
final def iOSTarget = System.getenv('SDK_NAME')?.startsWith("iphoneos") \
? presets.iosArm64 : presets.iosX64
If you only need arm64, and if it's just an iOS app, that seems likely, you can disable armv7 architecture in your build. Alternatively, you might try the combined ios() target.
We have a functional example here: https://github.com/touchlab/KaMPKit
It is using a fork of the cocoapods plugin, but besides isStatic, it's basically the same plugin.

Related

React Native Project Android Gradle Fail (React-Native-Reanimated Fail)

I was in the middle of coding an app using VS Code and react-native and after trying to install react-native-material-ripple I ran into the following error trying to build my app:
///////////////////////////////////////////////////////////////////////////////////////////////
FAILURE: Build failed with an exception.
Where:
Build file 'C:\Users\D'errah\Documents\Code\React\dowProjectMatcher\node_modules\react-native-reanimated\android\build.gradle' line: 89
What went wrong:
A problem occurred configuring project ':react-native-reanimated'.
java.io.IOException: The filename, directory name, or volume label syntax is incorrect
//////////////////////////////////////////////////////////////////////////////////////////////
The app was working perfectly before then. I went to the file in question and looked at the line the error mentioned:
mentioned line:
classpath += files(android.bootClasspath)
full file:
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
buildscript {
if (project == rootProject) {
// The Android Gradle plugin is only required when opening the android folder stand-alone.
// This avoids unnecessary downloads and potential conflicts when the library is included as a
// module dependency in an application project.
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
}
}
}
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 28)
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 16)
targetSdkVersion safeExtGet('targetSdkVersion', 28)
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
}
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url "$rootDir/../node_modules/jsc-android/dist"
}
google()
jcenter()
}
dependencies {
//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation "androidx.transition:transition:1.1.0"
}
def configureReactNativePom(def pom) {
def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text)
pom.project {
name packageJson.title
artifactId packageJson.name
version = packageJson.version
group = "com.swmansion.reanimated"
description packageJson.description
url packageJson.repository.baseUrl
licenses {
license {
name packageJson.license
url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename
distribution 'repo'
}
}
developers {
developer {
id packageJson.author.username
name packageJson.author.name
}
}
}
}
afterEvaluate { project ->
task androidJavadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += files(android.bootClasspath)
classpath += files(project.getConfigurations().getByName('compile').asList())
include '**/*.java'
}
task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) {
classifier = 'javadoc'
from androidJavadoc.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
include '**/*.java'
}
android.libraryVariants.all { variant ->
def compileTask
if (variant.hasProperty('javaCompileProvider')){
compileTask = variant.javaCompileProvider.get()
}else{
compileTask = variant.javaCompile
}
def name = variant.name.capitalize()
task "jar${name}"(type: Jar, dependsOn: compileTask) {
from compileTask.destinationDir
}
}
artifacts {
archives androidSourcesJar
archives androidJavadocJar
}
task installArchives(type: Upload) {
configuration = configurations.archives
repositories.mavenDeployer {
// Deploy to react-native-event-bridge/maven, ready to publish to npm
repository url: "file://${projectDir}/../android/maven"
configureReactNativePom pom
}
}
}
The problem is, I'm pretty sure that how that line was already even while the app was working. So I've spent the last few hours googling and haven't been able to figure out what cause the issue/how to fix it.
Any help would be GREATLY appreciated!
Things to note:
-using VS Code
-Was working before installing react-native-material-ripple (tried uninstalling, test, reinstalling, test)
Same error occurred for me also, please go through this documentation for proper installation setup for react-native-reanimate.
Install latest
yarn add react-native-reanimated#next
or
npm i react-native-reanimated#next
now go to android dir and gradlew clean, for more details go through below link
https://docs.swmansion.com/react-native-reanimated/docs/installation

How to add a dependency to build.gradle.kts for kotlin-multiplatform (kotlin 1.3.50)?

I started a new project with kotlin-multiplatform to create a library usable on iOS and Android using this tutorial :
https://play.kotlinlang.org/hands-on/Targeting%20iOS%20and%20Android%20with%20Kotlin%20Multiplatform/01_Introduction
It seems to work fine but I wanted to add the Serialization library mentioned at the end of the tutorial (https://github.com/Kotlin/kotlinx.serialization) and I can't make it work.
The setup guide in the library is not in Kotlin DSL so I tried different things to adapt the code but without success. Here is my project gradle :
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
And now my build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
}
kotlin {
//select iOS target platform depending on the Xcode environment variables
val iOSTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iOSTarget("ios") {
binaries {
framework {
baseName = "SharedCode"
}
}
}
jvm("android")
sourceSets["commonMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:0.13.0")
}
sourceSets["androidMain"].dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0")
}
sourceSets["iosMain"].dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.13.0")
}
}
val packForXcode by tasks.creating(Sync::class) {
val targetDir = File(buildDir, "xcode-frameworks")
/// selecting the right configuration for the iOS
/// framework depending on the environment
/// variables set by Xcode build
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val framework = kotlin.targets
.getByName<KotlinNativeTarget>("ios")
.binaries.getFramework(mode)
inputs.property("mode", mode)
dependsOn(framework.linkTask)
from({ framework.outputDirectory })
into(targetDir)
/// generate a helpful ./gradlew wrapper with embedded Java path
doLast {
val gradlew = File(targetDir, "gradlew")
gradlew.writeText("#!/bin/bash\n"
+ "export 'JAVA_HOME=${System.getProperty("java.home")}'\n"
+ "cd '${rootProject.rootDir}'\n"
+ "./gradlew \$#\n")
gradlew.setExecutable(true)
}
}
tasks.getByName("build").dependsOn(packForXcode)
I have no errors but I cannot use the library in my code.
Can someone please explain how to integrate this dependency or any dependency with this setup ? What do I do wrong ?
Note : I'm using Android Studio 3.5.1, Gradle 5.4.1, Kotlin 1.3.50.
Ok, so I found the issue.. just the version of the library.. 0.13.0 not 0.14.0. No error is thrown when you sync a wrong library version. I hope this post helps someone anyway.

Android subprojects with Kotlin DSL

I'm working on migrating by Gradle build files to the Kotlin DSL and I encounter an issue.
On my parent build.gradle, I have the following piece of code
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Version.kotlin}"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
subprojects {
afterEvaluate { project ->
if (project.plugins.findPlugin('com.android.application') ?:
project.plugins.findPlugin('com.android.library')) {
android {
compileSdkVersion = Android.SDK_COMPILE
defaultConfig {
minSdkVersion Android.SDK_MIN
targetSdkVersion Android.SDK_TARGET
versionCode = Android.VERSION_CODE
versionName = Android.VERSION_NAME
}
...
}
}
}
}
This allows me to configure in only one place all the modules that are android applications or libraries.
However this doesn't seem to work when I migrated to kotlin:
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath(Dependency.androidGradle)
classpath(Dependency.kotlinGradle)
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
subprojects {
afterEvaluate {
if (project.plugins.findPlugin("com.android.application") != null ||
project.plugins.findPlugin("com.android.library") != null) {
android { <<<<------------ Unresolved reference: android
compileSdkVersion(Android.SDK_COMPILE)
defaultConfig {
minSdkVersion(Android.SDK_MIN)
targetSdkVersion(Android.SDK_TARGET)
versionCode = Android.VERSION_CODE
versionName = Android.VERSION_NAME
}
...
}
}
}
}
The error is Unresolved reference: android and it looks like the android{} block is not recognized by the script compiler.
My theory is that the if checking for the subproject type is not enough, and I might have to cast or get a reference to some object in which I can call the android{} block, but honestly I do not know enough.
Any clues?
Gradle Kotlin DSL determines the dependencies for each script from the gradle classpath plus the applied plugins. That's why its recommended to use the plugins { ... } block in the Kotlin DSL.
You need to add the android and kotlin plugins to your root without applying it.
plugins {
id("<android-plugin>") version "<plugin-version>" apply false
id("<kotlin-plugin>") version "<plugin-version>" apply false
}
Unfortunately, that will still not generate the static accessors for the root build script but it will give you access to the plugin classes within the script and you can reference them like:
subprojects {
// BasePlugin is the common superclass of the AppPlugin and LibraryPlugin which are the plugin classes that "com.android.application" and "com.android.library" apply
plugins.withType<BasePlugin> {
// BaseExtension is the common superclass of the AppExtension and LibraryExtension which are the extension classes registered by the two plugins to the name "android"
configure<BaseExtension> {
// This block is typed correctly
defaultConfig {
// ...
}
}
}
}

Gradle cannot find method android() for arguments (Gradle 2.2.3)

Gradle for my project isn't working. I've checked other questions that have had the same problem, but this one is in a newer version and I'm not sure how to solve it. I'm trying to get the Android SDK up and running for the first time, so I'm really new to this. Thorough answers are appreciated.
Here is my Gradle error:
Error:(22, 0) Could not find method android() for arguments [build_3bh8pl96cp64yo421v01fuk9s$_run_closure3#4b7fff2f] on root project 'Meet-upProject' of type org.gradle.api.Project.
And here is my build.gradle in root:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
dexOptions {
incremental true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
}
}
dependencies {
compile files('app/libs/junit-4.12-JavaDoc.jar')
}

Android Gradle Build Resource.getIdentifier() always returns 0

I'm getting started on porting my Game over to the new Gradle Build system for Android.
I'm using the Resource.getIdentifier() method to load some resources by name instead of ID. However, ever since switching to the Gradle build, this call always returns 0. The assets are included in the built jar, and the R.class in the dex file contains all of my resources and ID's as expected, so I am at a loss as to explain this. This code worked before I changed to the gradle build. My build.gradle is below:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
apply plugin: 'android'
dependencies {
compile 'com.android.support:support-v4:18.0.+'
}
android {
compileSdkVersion 18
buildToolsVersion "19"
defaultConfig {
minSdkVersion 10
targetSdkVersion 18
}
buildTypes {
debug {
packageNameSuffix ".debug"
}
release {
runProguard true
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
}
}
TIA.
D'oh! my problem was that Resources.getIdentifer() takes 3 parameters, one of which is the package name. The debug section of my gradle script was tacking on ".debug" to the package name on the device. Solution is to remove the .debug suffix in the build.gradle.

Resources