Kotlin File in Native iOS Project with Kotlin/Native - ios

I would like to include a Kotlin file that only performs data processing and network operations in an existing iOS project, while keeping native iOS UI code.
While I thought that this may be achievable with Kotlin/Native, the iOS samples (1,2) that I found that use Kotlin/Native seem to take over the iOS UI code as well.
Is including a Kotlin file for data transfer in iOS possible with Kotlin/Native without touching the UI code, and if so, what are the steps to do so?

Yes, it is possible in a cross-platform project to transfer data between Kotlin and native iOS UI Code by using Kotlin/Native. This allows to have a common code base for the data model based on Kotlin, while e.g. continuing to use native UI code for iOS.
The original proof:
The project https://github.com/justMaku/Kotlin-Native-with-Swift pointed me in the right direction, since it shows the essential steps to do so:
In a Swift UIViewController, it calls a wrapper function that shall receive a string from a Kotlin function. The call is mediated through a C++ layer, which itself starts the Kotlin runtime, passes the request to a Kotlin function, receives the string from it, and passes it back to the Swift UIViewController, which then displays it.
On the technical level, the project contains a script that compiles the Kotlin, C++, and Kotlin/Native part into a static library, which then can be called from the native iOS project.
To get the code to run, I had (after cloning from git) to perform a "git submodule sync" before running "./setup.sh".
To transfer data with a data model based on Kotlin, I would like to have a generic function, that can pass data to Kotlin, modify that data, and return the result back to the native iOS code. As a proof of principle, that such a function can be build, I extended the project to not only receive a string from Kotlin, but send one to Kotlin, append it, and send the result back.
Extension of the project:
Since there were some roadblocks in this seemingly simple extension, I lay out the steps for anybody interested. If you follow along, you should get the following displayed:
The text may be stupid, but it tells you, what happens.
The changes in ViewController.swift in the function viewDidAppear are:
let swiftMessage: String = "Hello Kotlin, this is Swift!"
let cStr = swiftMessage.cString(using: String.Encoding.utf8)
if let retVal = kotlin_wrapper(cStr) {
let string = String(cString: retVal)
...
}
You see the text that Swift sends to Kotlin in the wrapper function (in the end, the resulting 'string' variable will be displayed). One could directly pass the Swift String to the wrapper, but I wanted to highlight that the wrapper will consider the input and output as c-strings. Indeed, the file Kotlin Native-Bridging-Header.h inside the native iOS project now becomes:
extern const char* kotlin_wrapper(const char* swiftMessage);
On it goes to the file Launcher.cpp. Since the original file used a KString as result value of kotlin_main, I tried for some time to convert const char* to KString and pass that to kotlin_main. In the end I found, that it is much simpler to directly transfer the const char* variables to Kotlin, and do the transformation there with the functions that are given to us by Kotlin/Native.
My Launcher.cpp then became more compact than the original. Here is the complete file:
#include "Memory.h"
#include "Natives.h"
#include "Runtime.h"
#include "KString.h"
#include <stdlib.h>
#include <string>
extern "C" const char* kotlin_main(const char* swiftMessageChar);
extern "C" const char* kotlin_wrapper(const char* swiftMessageChar) {
RuntimeState* state = InitRuntime();
if (state == nullptr) {
return "Failed to initialize the kotlin runtime";
}
const char* exitMessage = kotlin_main(swiftMessageChar);
DeinitRuntime(state);
return exitMessage;
}
You see how the wrapper first starts the Kotlin runtime and then calls the function kotlin_main, which resides in the file kotlin.kt:
import konan.internal.ExportForCppRuntime
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ByteVar
import kotlinx.cinterop.cstr
import kotlinx.cinterop.nativeHeap
import kotlinx.cinterop.toKString
#ExportForCppRuntime
fun kotlin_main(cPtr: CPointer<ByteVar>): CPointer<ByteVar> {
val swiftMessage = cPtr.toKString()
val kotlinMessage = "Hello Swift, I got your message: '$swiftMessage'."
val returnPtr = kotlinMessage.cstr.getPointer(nativeHeap)
return returnPtr
}
The pointer is converted to a Kotlin String, and then used in the creation of the kotlinMessage (the example of a data transformation). The result message is then transformed back to a pointer, and passed through the wrapper back to the Swift UIViewController.
Where to go from here?
In principle, one could use this framework without touching the C++ layer again. Just define pack and unpack functions, that pack arbitrary data types into a string and unpack the string to the respective data type on the other side. Such pack and unpack functions have to be written only once per language, and can be reused for different projects, if done sufficiently generic. In practice, I probably would first rewrite the above code to pass binary data, and then write the pack and unpack functions to transform arbitrary data types to and from binary data.

You can use kotlin as a framework if you want, so the kotlin code stays in framework file so you can use some common code on both android and iOS without writing your complete iOS app in kotlin.
Use gradle to build your kotlin code in objc/swift compatible framework
In your build.gradle file
buildscript {
ext.kotlin_native_version = '0.5'
repositories {
mavenCentral()
maven {
url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:$kotlin_native_version"
}
}
group 'nz.salect'
version '0.1'
apply plugin: "konan"
konan.targets = ["iphone", "iphone_sim"]
konanArtifacts {
framework('nativeLibs')
}
It will generate two .framework files, one for simulator other for the actual device, put the framework in your project and link that to your project as any other third party framework.
Cmd: ./gradlew build
Note: Every time you change your kotlin files build and replace your
framework file as well(you can create a shell script and add that to
build phases to do that automatically).
Cheers !!!

Related

How to incorporate the C++ standard library into a Zig program?

In reading the documentation for zig, I was under the impression that zig could compile both C and C++ code. Consequently, I thought you could import a C++ file's header via #cImport and have zig build succeed. However, I can't seem to get this to work for a C++ library integration.
I first create my project, zig init-lib and then add my import to src/main.zig via the #cImport directive. Specifically, I #cInclude("hooks/hooks.h") the C++ header file of this library. If I attempt to zig build at this point, the build fails, unable to find the header. I fix this by modifying build.zig to lib.addIncludeDir("/usr/include/library").
Since this C++ library is now being parsed and uses the C++ standard library, the next error I get when I zig build is that the stdexcept header is not found. To fix this, I modify build.zig to lib.linkSystemLibrary("c++").
Lastly, and the error I'm stuck on now, is an assortment of errors in /path/to/zig-linux-x86_64-0.9.1/lib/libcxx/include/<files>. I get stuff like unknown type name '__LIBCPP_PUSH_MACROS, unknown type name 'namespace', or unknown type name 'template'.
Googling this, the only thing of partial relevance that I could find was that this is due to clang's default interpretation of .h files is as C files which obviously don't have namespace or template keywords, but I don't know what to do with that knowledge. LLVM on MacOs - unknown type name 'template' in standard file iosfwd
Does anyone have any insight as to how to actually integrate with a C++ (not pure C) library through zig?
Specifically, I #cInclude("hooks/hooks.h") the C++ header file of this library.
#cImport() is for translating C header files into zig so they can be used without writing bindings. Unfortunately, it does not support C++ headers. To use a C++ library, you'll have to write C bindings for it and then #cImport() those headers.
// src/bindings.cpp
#include <iostream>
extern "C" void doSomeCppThing(void) {
std::cout << "Hello, World!\n";
}
// src/bindings.h
void doSomeCppThing(void);
// build.zig
const std = #import("std");
pub fn build(b: *std.build.Builder) void {
const target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("tmp", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.linkLibC();
exe.linkSystemLibrary("c++");
exe.addIncludeDir("src");
exe.addCSourceFile("src/bindings.cpp", &.{});
exe.install();
}
// src/main.zig
const c = #cImport({
#cInclude("bindings.h");
});
pub fn main() !void {
c.doSomeCppThing();
}

How to reflect Dart library name?

Is there a way to reflect specific library properties (like the library name) in Dart?
How do you get the library object reference?
First of all, not all Dart libraries have names. In fact, most don't. They used to, but the name isn't used for anything any more, so most library authors don't bother adding a name.
To do reflection on anything, including libraries, you need to use the dart:mirrors library, which does not exist on most platforms, including the web and Flutter.
If you are not running the stand-alone VM, you probably don't have dart:mirrors.
With dart:mirrors, you can get the program's libraries in various ways.
library my.library.name;
import "dart:mirrors";
final List<LibraryMirror> allLibraries =
[...currentMirrorSystem().libraries.values];
void main() {
// Recognize the library's mirror in *some* way.
var someLibrary = allLibraries.firstWhere((LibraryMirror library) =>
library.simpleName.toString().contains("name"));
// Find the library mirror by its name.
// Not great if you don't know the name and want to find it.
var currentLibrary = currentMirrorSystem().findLibrary(#my.library.name);
print(currentLibrary.simpleName);
// Find a declaration in the current library, and start from there.
var mainFunction = reflect(main) as ClosureMirror;
var alsoCurrentLibrary = mainFunction.function.owner as LibraryMirror;
print(alsoCurrentLibrary.simpleName);
}
What are you trying to do, which requires doing reflection?

How to get a field's type by using CDT parser

I'm trying to extract c++ source code's info.
One is field's type.
when source code like under I want to extract info's Type when info.call() is called.
Info info;
//skip
info.call(); //<- from here
Trough making a visitor which visit IASTName node, I tried to extract type info like under.
public class CDTVisitor extends ASTVisitor {
public CDTVisitor(boolean visitNodes) {
super(true);
}
public int visit(IASTName node){
if(node.resolveBinding().getName().toString().equals("info"))
System.out.println(((IField)node.getBinding()).getType());
// this not work properly.
//result is "org.eclipse.cdt.internal.core.dom.parser.ProblemType#86be70a"
return 3;
}
}
Assuming the code is in fact valid, a variable's type resolving to a ProblemType is an indication of a configuration problem in whatever tool or plugin is running this code, or in the project/workspace containing the code on which it is run.
In this case, the type of the variable info is Info, which is presumably a class or structure type, or a typedef. To resolve it correctly, CDT needs to be able to see the declaration of this type.
If this type is not declared in the same file that's being analyzed, but rather in a header file included by that file, CDT needs to use the project's index to find the declaration. That means:
The AST must be index-based. For example, if using ITranslationUnit.getAST to create the AST, the overload that takes an IIndex parameter must be used, and a non-null argument must be provided for it.
Since an IIndex is associated with a CDT project, the code being analyzed needs to be part of a CDT project, and the project needs to be indexed.
In order for the indexer to resolve #include directives correctly, the project's include paths need to be configured correctly, so that the indexer can actually find the right header files to parse.
Any one of these not being the case can lead to a type resolving to a ProblemType.
Self response.
The reason I couldn't get a binding object was the type of AST.
When try to parse C++ source code, I should have used ICPPASTTranslationUnit.
There is no code related this, I used IASTTranslationUnit as a return type of AST.
After using ICPPASTTranslationUnit instead of IASTTranslationUnit, I solved this problem.
Yes, I figure it out! Here is the entire code which can index all files in "src" folder of a cpp project and output the resolved type binding for all code expressions including the return value of low level API such as memcpy. Note that the project variable in following code is created by programatically importing an existing manually configured cpp project. I often manually create an empty cpp project and programatically import it as a general project (once imported, Eclipse will automatically detect the project type and complete the relevant configuration of CPP project). This is much more convenient than creating and configuring a cpp project from scratch programmatically. When importing project, you'd better not to copy the project or containment structures into workspace, because this may lead to infinitely copying same project in subfolder (infinite folder depth). The code works in Eclipse-2021-12 version. I download Eclipse-For-cpp and install plugin-development and jdt plugins. Then I create an Eclipse plugin project and extend the "org.eclipse.core.runtime.applications" extension point.
In another word, it is an Eclipse-Application plugin project which can use nearly all features of Eclipse but do not start the graphical interface (UI) of Eclipse. You should add all cdt related non-ui plugins as the dependencies because new version of Eclipse does not automatically add missing plugins any more.
ICProject cproject = CoreModel.getDefault().getCModel().getCProject(project.getName());
// this code creates index for entire project.
IIndex index = CCorePlugin.getIndexManager().getIndex(cproject);
IFolder folder = project.getFolder("src");
IResource[] rcs = folder.members();
// iterate all source files in src folder and visit all expressions to print the resolved type binding.
for (IResource rc : rcs) {
if (rc instanceof IFile) {
IFile f = (IFile) rc;
ITranslationUnit tu= (ITranslationUnit) CoreModel.getDefault().create(f);
index.acquireReadLock(); // we need a read-lock on the index
ICPPASTTranslationUnit ast = null;
try {
ast = (ICPPASTTranslationUnit) tu.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
} finally {
index.releaseReadLock();
}
if (ast != null) {
ast.accept(new ASTVisitor() {
#Override
public int visit(IASTExpression expression) {
// get the resolved type binding of expression.
IType etp = expression.getExpressionType();
System.out.println("IASTExpression type:" + etp + "#expr_str:" + expression.toString());
return super.visit(expression);
}
});
}
}
}

How to build Unity3d Plugin for iOS

I have a very tiny Objective-C library built for iOS and I want to export it to Unity. I understand the basic process of writing a csharp wrapper that marshals all the invocations to native library, but I completely have no idea where to start. Could anyone please explain step-by-step how to create a unity package with my library so I could also distribute it to other developers.
Unity3d documentation is pretty brief and does not explain anything.
Thanks.
Okay, after playing few days with Unity3d on Mac I finally figured it out. All the code in this guide is dummy. I have written this stuff in 15 minutes or so, so don't be bothered by mistakes and typos.
1) Open Unity, create new project (File -> New Project) and save it somewhere
2) When the project is generated it has the following structure:
ProjectName/Assets (That's what you need)
ProjectName/Library (Nevermind what's there)
ProjectName/ProjectSettings (You don't care about it)
ProjectName/ProjectName.sln (MonoDevelop project)
3) Go to ProjectName/Assets and create the following folders: Plugins/iOS, so in the end you'll have a folder structure like this: ProjectName/Assets/Plugins/iOS
4) Put your compiled library (.a) file and necessary headers inside of ProjectName/Assets/Plugins/iOS or copy the source code of your library there (.mm, .h, .m, etc..). Remember, normally you can only access C-functions from C#, so you'll have to wrap your Objective-C stuff in C-code somehow, in my case all Objective-C objects were implemented in a form of Singleton so it wasn't hard to make a C-style wrapper around, for instance:
CWrapper.h:
extern "C" void MySDKFooBarCFunction();
CWrapper.mm
#import "CWrapper.h"
#import "MyObjectiveCLibrary.h" // your actual iOS library header
void MySDKFooBarCFunction() {
[MyObjectiveCLibrary doSomeStuff];
}
5) Then go to ProjectName/Assets and create a folder for CSharp wrapper class(es), call it whatever you want, for example: ProjectName/Assets/MySDK
6) Inside of MySDK folder create MySDK.cs file, the dummy example of C# wrapper would look like this:
using UnityEngine;
using System;
using System.Runtime.InteropServices;
public class MySDK
{
// import a single C-function from our plugin
[DllImport ("__Internal")]
private static extern void MySDKFooBarCFunction();
// wrap imported C-function to C# method
public static void FooBarCFunction() {
// it won't work in Editor, so don't run it there
if(Application.platform != RuntimePlatform.OSXEditor) {
MySDKFooBarCFunction();
}
}
}
7) Create a shell script to pack this stuff into .unitypackage and put it next to your project folder (not inside). Adjust EXPORT_PATH and PROJECT_PATH variables in the script for your needs.
#!/bin/sh
WORKDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
UNITY_BIN="/Applications/Unity/Unity.app/Contents/MacOS/Unity"
EXPORT_PATH="${WORKDIR}/ProjectName.unitypackage"
PROJECT_PATH="${WORKDIR}/ProjectName"
ASSETS_PATH="Assets"
$UNITY_BIN -batchmode -quit \
-logFile export.log \
-projectPath $PROJECT_PATH \
-exportPackage $ASSETS_PATH $EXPORT_PATH
8) Run the created bash script to get your package build. All stuff from Assets will be included in XCode project for your Unity Project when you generate it via File -> Build Settings in Unity Editor. You can use generated package to distribute your code to other developers so they can simply include your library to their Unity projects by double clicking on the package file.
Don't forget to shutdown Unity Editor when you run this script, otherwise it may fail to build a package.
If you have some issues and package does not show up, this script always prints log to export.log
Next steps make sense only if you want to make a Demo unity project for your library (good for testing at least)
9) You can put created Unity project (ProjectName.unity) to Assets/MySDKDemo so you have a demo inside of your package.
10) Create a simple script for your Demo Unity3d scene at Assets/MySDKDemo/MySDKDemo.cs, for example:
using UnityEngine;
using System;
using System.Collections;
public class MySDKDemo : MonoBehaviour
{
private GUIStyle labelStyle = new GUIStyle();
private float centerX = Screen.width / 2;
// Use this for initialization
void Start ()
{
labelStyle.fontSize = 24;
labelStyle.normal.textColor = Color.black;
labelStyle.alignment = TextAnchor.MiddleCenter;
}
void OnGUI ()
{
GUI.Label(new Rect(centerX - 200, 20, 400, 35), "MySDK Demo", labelStyle);
if (GUI.Button(new Rect(centerX - 75, 80, 150, 35), "DoStuff"))
{
MySDK.FooBarCFunction();
}
}
}
11) Go to Unity Editor. Find the "Main Camera" in left sidebar in Unity Editor, select it and in the bottom of Inspector panel (right sidebar) click on AddComponent, select Scripts -> MySDKDemo script
12) Build the XCode project and run on device.
Few notes
1) Plugins don't work in Unity Editor, simply because they're not compiled in the real-time, well, not sure but probably until you use C# in your plugins, probably C# stuff gets linked immidiately and works in Editor environment.
2) This post does not cover marshaling, or data/memory management between native <-> managed code, as it is very well documented.
Interop with Native Libraries # Mono project
3) Callbacks from C# to C can be passed using C# delegates, on C-side you use standard functions declarations, on C# side you declare delegates with the same signature. It seems that booleans, integers and strings (C: char*) are marshalled flawlessly (I don't talk about memory management policy and who's responsible to release memory or return value policies).
However it will not work on iOS builds out-of-box due to platform limitations, but C#-to-C callbacks still can be implemented using MonoPInvokeCallbackAttribute, useful links on this topic:
Reverse Callbacks # Xamarin Docs
MonoPInvokeCallbackAttribute example # Xamarin Forums
Actually in Unity 4 there's AOT.MonoPInvokeCallbackAttribute already implemented, it's limited to static delegates that can be passed to unmanaged code, but still better than nothing.
4) There's a way to get Unity RootViewController using UnityGetGLViewController function. Just declare this function in your implementation file, i.e.:
extern UIViewController *UnityGetGLViewController();
And use UnityGetGLViewController() whenever you need to get an access to RootViewController.
5) There's much more magic and ugly stuff in details, keep your C interfaces as simple as possible otherwise marshalling can become your nightmare and also keep in mind that managed-to-unmanaged is generally expensive.
6) You definitely use some frameworks in your native code and you don't want linker problems. For example, if you use Keychain in your library then you need to include Security.framework into Xcode project.
I suggest to give a try to XUPorter, it helps Unity to integrate any additional dependencies into Xcode project.
Good luck!

How to reference another file in Dart?

I know you can use the library, import and even #import, but which is correct?
I have got two files, MainClass.dart and Library.Dart, and I want to add a reference to Library.dart in MainClass.dart. How can I do that?
Firstly let me just preface this by saying please do not use the hash symbol before import or library or anything else. This is an old syntax that is being deprecated. So we no longer want to use #import('...') The correct syntax is:
import 'some_file.dart';
That said, there are two different things we can do to access different dart source files within our current file. The first is to import the file. We use this such as in your case when you want to bring a different library into the current file (or more accurately current library).
Usually if your files are in the same directory, or a sub directory of the current one we would import them like this:
import 'lib/library.dart';
However If you are using the pub package layout you can also use some special short-cut references as well to import files (particularly from other packages you've imported). I highly suggest reading the documents on the pub site, as most applications and libraries are designed with this in mind. It also has suggestions on best naming conventions such as filenames in all lower case, and using underscore for spaces, and directory layouts.
The other important thing to know about bringing a dart file into another file, is that we can use the part and part of directives. This used to be called #source but was changed (with the removal of the hash sign) to reduce confusion. The part directive is used when we want to write a single library which spans multiple files. Say for instance you have an Awesome Library, which is starting to get a little large for a single file. We will create the main file of the library (not to be confused with the main method). This file will usually have the same name as the library itself.
// awesome_library.dart
library awesome_library;
import 'dart:math';
import '...';
// this injects all the content of secret_file.dart
// into this file right here almost as if it was
// here in the first place.
part 'src/secret_file.dart';
// The rest of our file here
// ...
The part directive basically takes everything from our src/secret_file.dart and inserts it into that part of the file. This allows us to split our huge Awesome Library into multiple smaller files that are easier to maintain. While not specifically required, it is helpful to use the part of directive in our secret_file.dart to help the editor know that it is "part of" the library.
// secret_file.dart
part of awesome_library;
// ... Rest of our secret_file code below.
Note that when using a part file like this, the part(s) (that is everything that is not the main file of the library) cannot import or use library declarations themselves. They import whatever is imported into the the main file, but they cannot add any additional imports.
For more information about library see this link.
Importing your own created libraries:
You will be importing the filename.dart and not the name of your library.
So if the name of your library is: myLib and it is saved in the file: someDartFile.dart you will have to
import 'someDartFile.dart';
If you have on Windows a library at: K:\SomeDir\someFile.dart you will need to write:
import '/K:/SomeDir/someFile.dart';
example:
import 'LibraryFile.dart'; //importing myLib
void main(){
//a class from myLib in the LibraryFile.dart file
var some = new SomeClassFromMyLibrary();
}
myLib in LibraryFile.dart:
library myLibrary;
import 'dart:math';
class SomeClassFromMyLibrary{
String _str = "this is some private String only to myLibrary";
String pubStr = "created instances of this class can access";
}
Here a full example.
//TestLib.dart
import 'LibFile.dart'; //SomeLibrary
void main() {
print("Hello, World!");
LibFile l = new LibFile();
print(l.publicString);//public
print(l.getPrivateString);//private
print(l.getMagicNumber); //42
}
//LibFile.dart
library SomeLibrary;
part 'LibFile2.dart';
class LibFile {
String _privateString = "private";
String publicString = "public";
String get getPrivateString => _privateString;
int get getMagicNumber => new LibFile2().number;
}
//LibFile2.dart
part of SomeLibrary;
class LibFile2 {
int number = 42;
}
Although i am answering very late, but the answer may help new developer.
Always use pubspec.yaml file in your dart package(application/library).
once you run pub get command it will add your local library in the dependencies list in .packages file.
Consider i have following project structure.
To refer to the content of greeting.dart in my main.dart file i should add the library as below
import 'package:my_project_name/greeting.dart'
Once imported we can use the content of greeting.dart file in our main.dart file.
Note: we have not used the actual path as you can see 'lib' directory is missing.
First make sure that's the name which you have mentioned in pubspec.yaml and the file you want to import are sharing the exact same name
example:
pubspec.yaml
name: flutter_wordpress_app
description: flutter wordpress app
...
....
// dirOne/dirTwo/greeting.dart
class FavArticleBloc {
// Your code goes here
}
import 'package:flutter_wordpress_app/dirOne/dirTwo/greeting.dart'
void main(){
var some = new FavArticleBloc();
}
But
in the main.dartyou don't need to specify
import 'package:flutter_wordpress_app
just do like below
import 'dirOne/dirTwo/greeting.dart

Resources