I am working on a library that is supported on many platforms including Android. This library is unit tested with the Google Test infrastructure. I am currently using Visual Studio 2015's cross platform features to build, deploy and debug. The test suite is getting considerably large and it takes a while to run the whole thing. With the Google Test infrastructure, it is possible to pass a command line argument to filter out the tests to be ran (--gtest_filter...). For platforms such as Windows, PS4 and XboxOne, this is easy to achieve inside Visual Studio by setting it in Project Properties -->Configuration Properties --> Debugging --> Command Arguments. However for the cross-platform developpment projects and package (AndroidProj), this Debugger property doesn't seem to exist. Here'a snapshot of Android Native-Activity Project Properties.
I am aware that the Visual GDB extension offers a similar feature to the one I am looking for as shown here, but this is not a viable option as I would like to avoid paying for the extension license.
How can I provide command line arguments to the Android Debugger the same way I can do it for the Local Windows Debugger for example?
A colleague of mine found the answer not too long after I posted this question. Here's how we solved our issue.
In VS2015, in the property pages of the Android cross-platform Package/App project (Androidproj), more precisely in the Debugging tab, there is the Launch Activity field. This field can be used to pass command line intent arguments. When you launch the debugger after installing the package, it will execute the following command:
adb.exe am start -D -n com.YourPackageName/TheContentOfLaunchActivityField.
In the Launch Activity field by default the launcher activity is specified (android.app.NativeActivity), but you can provide further intent arguments. A list of them can be found in this documentation: https://developer.android.com/studio/command-line/adb.html#IntentSpec.
In our situation, we needed to provide string data to our app (e.g.: --gtest_filter=...), so we used the intent argument -e extra_key extra_value.
Inside our main function we can retrieve the values of the extras using the following piece of code and some parsing (not shown). It uses the JNI (Java Native Interface).
JNIEnv* env = NULL;
state->activity->vm->AttachCurrentThread(&env, 0);
Private::JNIObjRef nativeActivityObject(env, state->activity->clazz);
jclass nativeActivityClass = env->GetObjectClass(nativeActivityObject.Get());
jmethodID getIntentID = env->GetMethodID(nativeActivityClass, "getIntent", "()Landroid/content/Intent;");
Private::JNIObjRef intentObject(env, env->CallObjectMethod(nativeActivityObject.Get(), getIntentID));
jclass intentClass = env->FindClass("android/content/Intent");
jmethodID getExtrasID = env->GetMethodID(intentClass, "getExtras", "()Landroid/os/Bundle;");
Private::JNIObjRef extrasObject(env, env->CallObjectMethod(intentObject.Get(), getExtrasID));
Related
I have some code that is written in Java and Kotlin for Android; the Java part can be translated into Kotlin using the Android Studio. Most of this code is business; that means, independent on any hardware or platform specifics; some Android specific classes (like "Bitmap") can be replaced by abstract or general self-defined classes.
As already known, Kotlin business code can be used in multiplatform applications for Android and iOS. Description here : https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html .
Xamarin is used for multiplatform apps, too.
On the other hand, there is a way to include Kotlin code in Xamarin projects. For this purpose, the Xamarin.Kotlin.StdLib is used : https://libraries.io/nuget/Xamarin.Kotlin.StdLib .
My question: Is it possible to develop a Xamarin project (maybe with Xamarin Forms) that includes the Kotlin business code and will work in both Android and iOS environments?
Here are some instructions.
ANDROID STUDIO
Create a new Project: "File -> New -> New Module -> Kotlin
Multiplatform Shared Module".
Follow these instructions:
https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html
until "Run your cross-platform application on Android".
For Android we're finished. Following steps are only for iOS.
We now assume that there is a module with the name "shared". If this module has another name, please replace it in the following instructions.
XCODE:
The following instructions are similar to that in https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html#make-your-cross-platform-application-work-on-ios . The difference is that we don't want to build the app now, but a framework.
File New - Project.
Select the template for "Framework" and click "Next".
Choose a product name (for example, "KmmExample"). Language:
Objective C
Build Phases - New Run Script Phase:
cd "$SRCROOT/.."
chmod +x gradlew
./gradlew :shared:embedAndSignAppleFrameworkForXcode
Move the Run Script phase up so that it is located after the
"Dependencies" item.
On the Build Settings tab, switch to "All" build settings.
In the Search Paths paragraph, specify the Framework Search Path for both Debug and Release:
$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)
In the Linking paragraph:
Specify the "Mach-O Type" as "Static Library".
Specify the Other Linker Flags as
$(inherited) -framework shared
In the Architectures paragraph, "Architectures" may be unchanged or changed to "$(ARCHS_STANDARD_INCLUDING_64_BIT)".
Build the project.
If successful, there will be a folder structure inside "shared/build". There will be a subfolder "xcode-frameworks". In the "Debug" resp. "Release" directory, there will be subfolder(s) with the name(s) of the iOS device(s) or simulator(s). For example, "iphonesimulator15.5". It contains another subfolder: "shared.framework". In the "Headers" you find a "shared.h", and there is the library itself: "shared". (In the "shared/build" folder there will be also a "bin" directory with device and simulator names containing "debugFramework" and similar structures inside.)
OBJECTIVE SHARPIE
Download the "Objective Sharpie" tool
(https://learn.microsoft.com/en-us/xamarin/cross-platform/macios/binding/objective-sharpie/)
In order to create "ApiDefinitions.cs" from shared.h using
"sharpie" follow these steps:
Open a Termimal (Command-line) session.
Change to the directory where "shared" is located.
Type:
sharpie bind --output=./SharpieOutput --namespace=Shared --sdk iphoseos15.5 -scope ./shared ./shared/build/xcode-frameworks/Debug/iphonesimulator15.5/shared.framework/Headers/shared.h
(please replace "iphoneos15.5" by the correct SDK and "Debug/iphonesimulator15.5" by the correct folder name)
You also can choose another namespace instead of "Shared". It will be specified in the ApiDefinitions.h.
If successful, a "ApiDefinitions.cs" will be in a new subfolder
"SharpieOutput".
VISUAL STUDIO / XAMARIN
Use Visual Studio 2019 or 2022 or higher.
Create a new Solution, say, "MyApp".
"MyApp" should contain four projects: "MyApp", "MyApp.Android",
"MyApp.iOS".
Here, we don't talk about "MyApp.Android".
Right-click on the solution name and add a "New Project". Choose "iOS - Library - Bindings Library". Its name may be "MyApp.iOS.Binding".
Replace the ApiDefinitions.cs by that that has been created in the precding step.
Add the "shared" library (created by XCode in one of the steps above) as a "Native Library".
Right-click on ApiDefinitions.cs and change "Build action" =
"ObjcBindingApiDefinition".
When you now open ApiDefinitions.cs, you'll probably see a lot of errors and marked lines. They may be handled as follows:
For the "[Verify]" attribute, please check here: https://learn.microsoft.com/en-us/xamarin/ios/platform/binding-swift/walkthrough#build-a-binding-library , section 5.
If "NativeHandle" creates a compiler error, please add at the top:
#if !NET
using NativeHandle=System.IntPtr;
#endif
You may remove "using" with the shared module ("using shared")
If you encounter errors like "Cannot declare instance members in a static class (CS0708) and "static classes cannot implement interfaces" (CS0714): try to comment out or remove the attribute "[Category]".
"[Unavailable (PlatformName.Swift)]" may be removed if yielding an error.
Handle typed classes resp. Interfaces with "<T>". For example, the "<T>" attribute should be added to some interfaces representing typed classes. In some cases special handling is necessary.
CS0246: In some cases, when an element cannot be found, an attribute "[BaseType(typeof(SharedBase))]" may help (assuming that the interface SharedBase is defined at the beginning of this file).
If, during a build run, there are warnings CS8767 ("… hides inherited member"), add the attribute [Override] above these members. For "New()", however, add "[New]" instead.
In case of linker errors MT5211 "Native linking failed, undefined Objective-C class …", add the attribute "[Protocol]" in front of the interface definition:
[BaseTye (typeof (NSObject))]
[Protocol]
public interface MyInterface { … }
Other compiler / linker errors (e.g. " … was built for newer iOS version (…) than being linked …" possibly can result in warnings after that.
The "MyApp" project contains all platform independent code. Those classes which contain platform dependent parts should be defined as interfaces.
"MyApp.Android" and "MyApp.iOS" should implement these interfaces. For "MyApp.iOS", "MyApp" and "MyApp.iOS.Binding" should be added as References. The classes implementing those interfaces now can use the interfaces defined in ApiDefinitions.h.
End of instructions.
I have posted the same question in another forum - https://learn.microsoft.com/en-us/answers/questions/875957/use-business-code-for-android-and-ios-written-in-k.html - and I have posted a possible answer, see the answer of Jul 19, 2022. Spoiler: yes, it is possible, but not directly, and it is complicated.
I want write simple application in Python for Android using kivy. Sadly when I start example code I see only splash screen and few second later application finish work. There is a huge problem with debugging because adb on Linux Mint does not detect my device.
Can someone look at my code and tell my why?
To build application I use buildozer. You can also see create_env script to check all dependencies are there.
Best regards.
Draqun
EDIT:
I started debugging my application. Conclusion:
buildozer + python3 + kivy is a bad idea
if I use kivy.uix.button.Button when text attribute is str than I got exception "AttributeError: 'str' object has no attribute 'decode'"
if I use kivy.uix.button.Button when text attribute is bytes than I got exception "ValueError: Button.text accept only str"
It looks like loop with no solution. Some idea when I should report it?
Exception is in .buildozer/android/platform/build/build/python-installs/pad/android/init.py" file so it does not look like kivy and/or buildozer exception.
I've used python-for android tool and faced with the same errors. But in my case, app didn't run at all - crashed from splash screen. Finally, I've found a solution. You can try the same way.
So my pipeline was python3 + python-for-android (p4a tool, python-for-android, from master branch) + kivy (1.10.1)
There is a file "_android.pyx" for android building recipe (full list of avaliable p4a recipes you can see by command p4a recipes). This file is, possibly, used by Buildozer, and exactly used by P4A during APK building procedure. You need to fix it.
You may find it's location in Ubuntu (for example) via:
sudo updatedb
locate _android.pyx
It's path should be something like:
~/.local/lib/python3.6/site-packages/pythonforandroid/recipes/android/src/android/_android.pyx
There should be a string:
python_act = autoclass(JAVA_NAMESPACE.decode('utf-8') + u'.PythonActivity')
so you should change it - something like this:
python_act = autoclass(str(JAVA_NAMESPACE) + u'.PythonActivity'),
or just use some hardcode:
python_act = autoclass("org/kivy/android/PythonActivity")
Or there might be the other decode() usage in sources.
The reason: differences between Python2 and Python3 - the decode() method is usable on the equivalent binary data type in either Python 2 or 3, but it can’t be used by the textual data type consistently between Python 2 and 3 because str in Python 3 doesn’t have the method decode function has different realisation in Python3. More details are here:
pyporting features
issues p4a's github
Hope, it will help you somehow.
I'm trying to call a Python script from Tasker using SL4A on my Android (4.4) phone. I'm using the Run SL4A Script task for this. As a test exercise, I want to pass a string from Tasker and use it (for now just print it) in Python.
According to the link below, this can be done by setting the 'Pass Variables' field in the Run SL4A Script task and picking it up with the Android getIntent method in Python. (https://groups.google.com/forum/#!topic/taskerpro/mQIv1PBu3PU)
Here's my Python script:
import android
droid = android.Android
params = droid.getIntent().result[u'extras']
print params[0]
However when I run the task I get the following error in SL4A:
AttributeError: type object 'Android' has no attribute 'getIntent'
Anyone know why I get this and how to solve it? I can't find any reference to it elsewhere.
I don't know about calling from Tasker, but the Python script runs fine stand-alone on SL4A Release 6 and Python interpreter Py4A Release 5.
If you don't have everything installed yet, here are some some slides I recently presented at an Android developers meetup.
I think you are simply missing the parentheses in your Android imports.
I use:
import android
droid = android.Android()
you can also try:
from android import Android
droid = Android()
this makes Android an object in python properly and you should be able to call the getIntent and other functions properly.
and to save time testing if the android module is functional I also add:
def toast(x):
x = str(x)
droid.makeToast(x)
then you can pass variables to the newly defined toast(x) function.
Hope I've helped!
Please pardon my ignorance, relatively new to working with Unity3D. I am working on automating Unity3d builds from the command line.
I am looking for command line arguments to build apk & xcode project.
Unity's documentation does mention arguments to build a standalone Mac OSX player (-buildOSXPlayer) and a standalone Windows player (-buildWindowsPlayer) but not for android and iOS.
Any help would be really appreciated. Thanks.
Start with Unity's own documentation for command line builds for iOS and android.
For example, put this script in your Assets/Editor folder:
// C# example
using UnityEditor;
class Autobuilder
{
[MenuItem ("File/AutoBuilder/iOS")]
static void PerformBuild ()
{
string[] scenes = { "Assets/MyScene.unity" };
string buildPath = "../../../Build/iOS";
// Create build folder if not yet exists
Directory.CreateDirectory(buildPath);
BuildPipeline.BuildPlayer(scenes, buildPath, BuildTarget.iOS, BuildOptions.Development);
}
}
You can actually run this script in the Unity application by going to File -> Autobuilder -> iOS
To run on command line, it looks something like this:
/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -executeMethod Autobuilder.PerformBuild -email me#email.com -password myPassword
Of course, you're going to want to check the debug log for any errors:
Mac OS X ~/Library/Logs/Unity/Editor.log
Windows XP C:\Documents and Settings\username\Local Settings\Application Data_\Unity\Editor\Editor.log
Windows Vista/7 C:\Users\username\AppData\Local\Unity\Editor\Editor.log
The -executeMethod command line parameter is a very simple option to invoke any function in any of your scripts - which you can then use to do pretty much anything, including firing off an Android build.
Is it possible to tell Eclipse to use some extra arguments for aapt (-0 in specific)?
I have been looking for past couple of hours and the best hack I came up with was to create a wrapper for the aapt tool to inject the argument to the command line. The trouble with this approach is that whenever I should lose that wrapper, then I'll be quietly introducing a bug into my application.
I don't think it is possible without some sort of wrapper script as you mention.
Alternatively, you could use an Android ant script to build the release version of your application, as that lets you easily override the command line parameters used. It also helps you build things independently of the Eclipse plugin which is useful should you get into continuous integration.
Hopefully you wouldn't be quietly introducing a bug anyway due to at least smoke testing your app before release.
Thank you Christopher for your answer. Here is the aapt wrapper script I built in python for my purposes in case anyone needs it:
#!/usr/bin/env python
KEY=r'name-of-your-directory'
DIR='/../../path/to/your/include/res/'
import os
import re
import sys
mydir = os.path.dirname(os.path.realpath(__file__))
real_aapt = "%s/%s" % (mydir,"aapt-real")
#args = sys.argv[1:]
args = sys.argv
found=False
nextisdir=False
newargs=[]
for arg in args:
if re.search(KEY,arg):
found=True
if nextisdir:
nextisdir=False
newargs.append("--auto-add-overlay")
newargs.append("-S")
newargs.append(arg+DIR)
if found and arg == '-S':
nextisdir=True
os.execv(real_aapt,args+newargs)