How to generate a .framework depending from another with Kotlin/native? - kotlin-multiplatform

I have some dependencies issues with KMP and iOS Framework.
Here is some context:
I have 2 KMP modules:
An API module: define only interfaces
A classic lib use the API module as injection
I also have 2 android projects and 2 iOS projects:
an Android and iOS application (that use the KMP ClassicLib)
an Android and iOS lib that implement the API module
On Android, I have the following :
// KMP API project
public interface Foo
// KMP libA project
public class Bar {
fun doSomething(foo: Foo)
}
// ANDROID: libB project
import API
public class FooImpl: Foo { }
// ANDROID app
import libA
import libB
var foo = FooImpl()
var bar = Bar()
bar.doSomething(foo) // <----- Everything is fine here
but on iOS, I have this:
// iOS app
import libA
import libB
var foo = FooImpl()
var bar = Bar()
bar.doSomething(foo) // <----- Error here : FooImpl is of type APIFoo but here LibAAPIFoo is excpected
Indeed when I take a look into the generated headers, I have the following:
// KMP API.h
#protocol APIFoo
#end;
// KMP libA.h
#protocol LibAKAFoo // <----- here we have a redefinition of the protocol.
#end;
#interface Bar
- (void)doSomething:(KMPKAFoo)foo;
#ends;
I was expecting to have something more like :
// KMP API.h
#protocol APIFoo
#end;
// KMP libA.h
#include <API/API.h> // <----- import the API
#interface Bar
- (void)doSomething:(APIFoo)foo; // <----- use it
#ends;
Is there a special configuration that I'm missing into my build.gradle ?
I've tried to use compileOnly into the dependencies definition, but it had no effect and have the same behavior as implementation
val commonMain by getting {
dependencies {
compileOnly("com.poc.sample:KMPAPI:0.0.1")
}

You cannot create multiple Kotlin iOS frameworks and use them in the same project interchangeably. When the Kotlin compiler creates an iOS framework, it is its "own world", as in it includes everything you need (dependencies, etc). It's one big binary.
The summary is, the config you want is not possible. You can use multiple Kotlin iOS frameworks in the same project, but they need to be fully independent. They won't be able to communicate with each other.

Related

What's happening behind the scenes in XCTest's #testable?

I know that
#testable import MyModule
gives ability to explore non-public members of MyModule from a "test" (built with "testTarget") module MyModuleTests.
I need the same functionality in my "non-test" module. Not in production, just in debug mode.
My question is: do you know how to do this?
And related (I think, harder question): what magic is actually happening behind #testable?
To answer your question, for debugging purposes, you can actually use this. Let's say you have a workspace MyAwesomeWkspace and a project inside MyAwesomeProject.
Now, create a new framework aka module called MyAwesomeModule. Inside that module create a non-public class called Person.
If you try to use the class Person inside MyAwesomeProject by doing import MyAwesomeModule and then something like let p = Person() you will have an error.
But if you do #testable import MyAwesomeModule, the magic happens and you can now use the class.
Basically #testable allows you to test things that you didn't declare public. The annotation only works with import as you can see it here.
So in order to work, the target is compiled with -enable-testing so that you can have access to non-public members. At least based on what's here
Because, by default, the debug build configuration is compiled with -enable-testing, the example I showed you will work. But if you change the build config to release, you'll see an error saying Module .. was not compiled for testing since the release config is not built with the flag.
The Swift access control model, as described in the Access Control
section of The Swift Programming Language (Swift 4), prevents an
external entity from accessing anything declared as internal in an app
or framework. By default, to be able to access these items from your
test code, you would need to elevate their access level to at least
public, reducing the benefits of Swift’s type safety.
Xcode provides a two-part solution to this problem:
When you set the Enable Testability build setting to Yes, which is
true by default for test builds in new projects, Xcode includes the
-enable-testing flag during compilation. This makes the Swift entities declared in the compiled module eligible for a higher level of access.
When you add the #testable attribute to an import statement for a
module compiled with testing enabled, you activate the elevated access
for that module in that scope. Classes and class members marked as
internal or public behave as if they were marked open. Other entities
marked as internal act as if they were declared public.
More here
Late edit: One of the cool parts of swift is that is open source. So if you want to dive deep into the "magic", check it out: https://github.com/apple/swift
#testable import <module_name> and -enable-testing
[Swift access modifiers]
[Swift module]
consumer side uses #testable import -> producer side should use `-enable-testing` flag
producer side: enable -enable-testing
Enable Testability(ENABLE_TESTABILITY) - YES
Other Swift Flags(OTHER_SWIFT_FLAGS) - -enable-testing
consumer side: #testable
internal(default) and public access level for class is visible for current module as open
internal(default) access level for others(struct, enum) is visible for current module as public
If you build test schema(consumer) with #testable but producer doesn't include -enable-testing you get
Module '<module_name>' was not compiled for testing
Some experiments:
SomeModule
internal class SomeInternalClass {
internal func foo() { }
}
public class SomePublicClass {
public func foo() { }
}
internal class SomeInternalStruct {
internal func foo() { }
}
internal enum SomeInternalEnum: String {
case foo = "hello world"
}
Tests: If you omit #testable next errors will occur
import XCTest
#testable import ExperimentsTests
class ExperimentsTestsTests: XCTestCase {
func testExample() throws {
let someInternalStruct = SomeInternalStruct() //Cannot find 'SomeInternalStruct' in scope
someInternalStruct.foo()
let someInternalEnum = SomeInternalEnum(rawValue: "") //Cannot find 'SomeInternalEnum' in scope
SomeInternalEnum.foo //Cannot find 'SomeInternalEnum' in scope
}
class SomePublicSubClass: SomePublicClass { //Cannot inherit from non-open class 'SomePublicClass' outside of its defining module
override func foo() { } //Overriding non-open instance method outside of its defining module
}
class SomeInternalSubClass: SomeInternalClass { //Cannot find type 'SomeInternalClass' in scope
override func foo() { } //Method does not override any method from its superclass
}
}

What is the `using` keyword in Haxe?

I often see people use the keyword using in their Haxe code. It seem to go after the import statements.
For example, I found this is a code snippet:
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
using haxe.macro.Tools;
using Lambda;
What does it do and how does it work?
The "using" mixin feature of Haxe is also referred as "static extension". It's a great syntactic sugar feature of Haxe; they can have a positive effect on code readability.
A static extension allows pseudo-extending existing types without modifying their source. In Haxe this is achieved by declaring a static method with a first argument of the extending type and then bringing the defining class into context through the using keyword.
Take a look at this example:
using Test.StringUtil;
class Test {
static public function main() {
// now possible with because of the `using`
trace("Haxe is great".getWordCount());
// otherwise you had to type
// trace(StringUtil.getWordCount("Haxe is great"));
}
}
class StringUtil {
public static inline function getWordCount(value:String) {
return value.split(" ").length;
}
}
Run this example here: http://try.haxe.org/#C96B7
More in the Haxe Documentation:
Haxe static extensions in the Haxe Manual
Haxe static extensions tagged articles in the Haxe Code Cookbook

Dart Can't get logging statements to compile

I'm trying to learn how to implement logging using the examples/tutorial in:
http://blog.dartwatch.com/2013/05/campaign-to-use-real-logging-instead-of.html#comment-form
But having imported the libraries this line in main will not compile because the class 'PrintHandler' is not recognized and Google has not been a help in this case. My server application consists of a main and three classes. I'm new at Dart. Below I've extracted the logging code that I added.
In what library is 'PrintHandler'? Is this a class I need to write?
library server;
import 'package:logging_handlers/logging_handlers_shared.dart';
import 'package:logging/logging.dart';
final _serverLogger = new Logger("server"); // top level logger
void main() {
Logger.root.onRecord.listen(new PrintHandler()); // default PrintHandler
_serverLogger.fine("Server created");
}
class A {
}
class B {
}
class C {
}
It looks like the class was changed to LogPrintHandler but the tutorial and documentation were not updated.

"The native class hasn't been loading" error with my bindings

I'm trying to create bindings for GPUImage project, but none of binded classes is working.
For example, GPUImageView:
In ObjC it's declared like this (header in git):
#interface GPUImageView : UIView <GPUImageInput>
//then some fields, properties and methods I'm not interested in
So, my ApiDefinition.cs looks like this:
namespace GPUImage
{
[BaseType (typeof(NSObject))]
[Model]
interface GPUImageInput {
}
[BaseType (typeof(UIView))]
interface GPUImageView : GPUImageInput {
[Export ("initWithFrame:")]
IntPtr Constructor(RectangleF frame);
}
}
LinkWithAttributes:
[assembly: LinkWith ("libGPUImage.a", LinkTarget.Simulator | LinkTarget.ArmV7 | LinkTarget.ArmV7s, ForceLoad = true, Frameworks = "CoreMedia CoreVideo OpenGLES QuartzCore AVFoundation UIKit Foundation")]
It builds ok and creates dll. But when I try to use it in my project like this:
var iv = new GPUImageView (new RectangleF (0, 0, 100, 100));
Exception throwed:
Could not create an native instance of the type 'GPUImage.GPUImageView': the native class hasn't been loaded.
It is possible to ignore this condition by setting Class.ThrowOnInitFailure to false.
Stacktrace
After MonoTouch.ObjCRuntime.Class.ThrowOnInitFailure == false iv was created, but unusable (e.g. AddSubview(iv) show nothing).
I suppose there is something wrong with GPUImage.a file, but I don't know how to test it in any way.
Here is 7z with 2 projects in it: TryingBindings -- bindings themselves; TryingGPUImage -- bindings in use;
Thanks in advance.
P.S. Here is the link to this post on xamarin forums.
Thanks to Rolf Bjarne Kvinge
There are two problems:
1) The file with the LinkWith attribute (libGPUImage.linkwith.cs) is
not compiled. Just right-click the TryingBindings project, Add, Add
files and select it.
2) The native library does not contain code for i386 (simulator), only
arm (device). If you're building the native library yourself you can
either create a universal library that contain code for all the
architectures, or you can use several native libraries, each
supporting a different set of architectures, and just have a LinkWith attribute for each native library.
Bug 11497

How to use the [mixin] tag in AS3 applications?

I have the following two projects in in Flex Builder 3:
One AS3 library project (generates a SWC file)
One Flex application project (MXML Application)
The MXML Application references to the AS3 library project (Flex build path). So far, so good. I now want to run code automatically when an application uses the AS3 library. The [mixin] tag should do exactly what I need.
I followed the instructions from http://nondocs.blogspot.com/2007/04/metadatamixin.html and checked out the AutoQuick project. The latter is an example project by Adobe showing the use of the automation framework. In this project they are using the [mixin] tag (class AQAdapter).
I followed the examples but my code is not working. The static init method is not called. I added the library to the compiler arguments list that didn't work either.
How do I get this to work?
/* class to be automatically loaded */
package {
/* includes */
[mixin]
public class TestApp extends Sprite {
/* additional members */
private static var mContainer:DisplayObjectContainer;
private static var mInstance:TestApp;
/**
* #private
*/
public static function init(root:DisplayObject):void
{
if(!mInstance)
{
mContainer = root as DisplayObjectContainer;
mContainer.addEventListener(FlexEvent.APPLICATION_COMPLETE, applicationCompleteHandler);
}
}
}
}
With the [Mixin] tag, the static init() method will be called at application start-up, as long as the class is referenced directly or indirectly from the main application.
Also, you have to remember that this method is run in a static context, so you shouldn't reference methods or attributes that require an instance (non-static), without creating the instance first.
Link: http://adamflater.blogspot.com/2007/03/static-code-blocks.html

Resources