I have an aar package, I unzipped it, unzipped the classes.jar file as well, and now have a bunch of .kt and .class files a few of which I would like to edit. But all I see is class and method declaration with their body containing /* compiled code */. Where do I find the Kotlin code so I can edit it like we used to in Java class files?
Now this is my first time handling kotlin and frankly i don't even know the language. I am using android studio to open the files, and i know how to generate a read-only decompiled java version to understand the inner workings. That's how i figured out which file i need to edit.
I have also found some answers on stack that mention how converting kotlin to java and back to kotlin after editing is not a good idea, since the java file is not a perfect decompilation.
Here is the file I want to edit as it appears in AS:
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package ru.aviasales.screen.results.view
public final class ResultItemView public constructor(context: android.content.Context, attributeSet: android.util.AttributeSet) : ru.aviasales.ui.views.CardView {
private final val segmentViews: kotlin.collections.MutableList<ru.aviasales.screen.results.view.ResultSegmentItemView> /* compiled code */
public final fun onFavouritesButtonClicked(onClick: () -> kotlin.Unit): kotlin.Unit { /* compiled code */ }
protected open fun onFinishInflate(): kotlin.Unit { /* compiled code */ }
public final fun setData(viewModel: ru.aviasales.screen.results.viewmodel.ResultItem.TicketViewModel): kotlin.Unit { /* compiled code */ }
private final fun setUpAvailableSeatsCount(seatsCount: kotlin.Int, type: ru.aviasales.screen.results.viewmodel.ResultViewType): kotlin.Unit { /* compiled code */ }
private final fun setUpFavouritesButton(favoritesEnabled: kotlin.Boolean, addedToFavourites: kotlin.Boolean): kotlin.Unit { /* compiled code */ }
private final fun setUpPrice(price: kotlin.Long, passengersCount: kotlin.Int): kotlin.Unit { /* compiled code */ }
private final fun setUpSegments(segments: kotlin.collections.List<ru.aviasales.screen.results.viewmodel.SegmentViewModel>): kotlin.Unit { /* compiled code */ }
}
Is it even possible to edit these type of files ? if yes then Do i need a different editor or is there a different method to open such files ?
The simple answer after trying everything I could, is that you can't.
Luckily I was able to circumvent the issue, by creating a new activity. The aar package had its own MainActivity activity which was also kotlin class file. I decompiled the .class file, copy pasted the java code into my new activity and use then call the new activity from application file (since the MainActivity was being called automatically at start). I also faced the problem of some variables not initialising properly because of lateinit. I solved that by simply copying the variables through application from MainActivity using registerActivityLifecycleCallback and then calling my activity.
Related
I am working on an Android application that will call a .so file created by a different Android NDK application.
I have created the following folder structure in my project and copied over the .so files as seen below:
|--app:
|--|--src:
|--|--|--main
|--|--|--|--jniLibs
|--|--|--|--|--armeabi
|--|--|--|--|--|--libmylib.so
|--|--|--|--|--x86
|--|--|--|--|--|--libmylib.so
I call this library through my application via the following code:
static {
System.loadLibrary("mylib");
}
I then call the method from this shared object via the following code:
String str = stringFromJNI();
This does not work as the program looks for mangled function name as follows:
com.example.androidlibcall.MainActivity.stringFromJNI() where my .so function will be using a different package name and hence a different function name is generated.
I am not really sure what I need to do to call the functions from the external library, I assume I can create my own library and utilize dlopen() to load the external library and make calls to it, but was wondering if there are the other methods to achieve this or not.
My ultimate goal is to be able to create applications that can call pre-existing libraries that are on the mobile device, but since I am new to NDK/Android I am not sure what is the best method for this and have not found good examples to work with.
A lot of the pre-existing similar questions seem to be dealing with older versions of Android Studio that don't seem applicable anymore.
I am using the latest version of Android Studio (3.1.2) with Gradle 4.4 on Windows 7 machine.
Please advise.
Thanks!
Generally speaking, it's not a good idea to have native methods in application's MainActivity, but this should not worry us now that we are forging a workaround.
Assume that your new project has com.example.other.MainActivity.java, and you want to call the native method com.example.androidlibcall.MainActivity.stringFromJNI() from com.example.other.MainActivity.onCreate(). To do this, create a new Java class in your other app:
package com.example.androidlibcall;
public class MainActivity {
public static native String stringFromJNI();
}
and in your existing MainActivity class,
package com.example.other;
import static com.example.androidlibcall.MainActivity.stringFromJNI;
class MainActivity {
static {
System.loadLibrary("mylib");
}
}
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
String qq = stringFromJNI();
…
}
}
You see that com/example/androidlibcall/MainActivity.java contains no logic, no data, no code. It is only a wrapper that lets us easily use libmylib.so without rebuilding it.
I have an interface in C++/CLI I need to implement in C#, but I it is not visible. However I have other classes (abstract and concrete that I can inherit from).
My C++/CLI Interface:
namespace MyNamespace { namespace MySubnamespace {
public interface class ITestInterface
{
public:
property bool FirstProperty
{
bool get();
}
property bool SecondProperty
{
bool get();
}
};
}}
I have a Test project where I use all the functionality in my Managed Library, but the Interface never becomes visible.
How I try to use it in my C# Test project: (I tried using it from a Class Library Project also, and it doesn't work either).
public class Test: MyNamespace.MySubnamespace.ITestInterface
{
}
I get "Cannot resolve symbol 'ITestInterface'"
What am I missing?
Update
I kept trying different things following the comments to my question, and I found that if I include my .h file in some other .h file of my C++/CLI project, the class becomes visible.
Basically I just do:
#include "ITestInterface.h"
In one of my other .h files of the C++/CLI project and the Class becomes visible to the c# project.
Is there a way I could avoid doing that?
C++/CLI is similar to C++ in that only .cpp files are compiled directly. Header files are only compiled when included. This is why adding an #include for your interface header works.
There are several ways to make sure your code is included for a C++/CLI class:
Have both a .h and .cpp file (even if the .cpp file only includes the .h file it corresponds to)
Have only include files and then include all of the headers in one .cpp file (which may be empty other than the includes)
Have only .cpp files (which is fine if the other code does not reference this code)
Inside my template file I use the safeitemname template variable to define my class name. The Item Template is intended to create a class that subclasses MXApplication. The result after exporting the template and utilizing it to create a new class is essentially the class inherits from itself. If I try adding a namespace to the class, I just get the namespace prefixed before the value substituted for safeitemname.
Here is the Template class (trimmed for explanation purposes):
namespace $rootnamespace$
{
public class $safeitemname$ : MonoCross.Navigation.MXApplication
{
public override void OnAppLoad()
{
//Do the work
}
}
}
The result when I use the template to create MyApp is:
namespace MyNameSpace
{
public class MyApp : MonoCross.Navigation.MyApp
{
public override void OnAppLoad()
{
//Do the work
}
}
}
I've tried to export this template using VS2012 (and VS2013).
Any advice would be much appreciated. I've been trying to update my Item Templates in Visual Studio 2012 (they worked in 2010) but I keep running into this issue. I've tried it on several of my existing templates; and even tried recreating the .csproj and adding my existing templates to the .csprog file created using Visual Studio 2012. All of my attempts result in the same class inheritance issue.
This is the MSDN Doc I've been using for reference:
http://msdn.microsoft.com/en-us/library/vstudio/tsyyf0yh.aspx
The issue was apparent when looking at the .zip file created by the Export Template command. The .cs file contained within the template .zip read:
namespace $rootnamespace$
{
class $safeitemname$ : MonoCross.Navigation.$safeitemname$
{
public override void OnAppLoad()
{
//Do the work
}
}
}
The fix to get my template working was to edit the .cs file manually and replace the last $safeitemname$ with MXApplication and then stick the .cs file back in the .zip file where it came from.
I want to use one native library for a plurality of applications. Library has compiled through android build system and now located in /system/lib/. It can be loaded in application through System.LoadLibrary("libexample"). But method in library which should be declared like
JNIEXPORT jstring JNICALL Java_application1_MainActivity_method1
turning out unusable because library should be used by several applications. And of course this several applications have their own unique names. So I tried to named my method just like
JNIEXPORT jstring JNICALL method1
and call
public native String method1(String string);
But of course my application trying to find it as Java_application1_MainActivity_method1
How to call this method or how it should be named?
Updated:
I tried to use this(see post with green tick) tutorial to complete my project. I wrote
a library for using native method:
package com.example.mylib;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MyClass extends Activity {
public native static String MyMethod(String string);
static {
System.loadLibrary("nativeLibrary");
}
}
Then I trying to use it in my application:
// Some no interesting inclusions
import com.example.mylib.MyClass;
public class MainActivity extends ListActivity {
// Some no interesting code.
MyMethod(file.getAbsolutePath())
//Some no interesting code
}
And it working as I need! But now I confused that my import com.example.mylib.MyClass;
"never used" in eclipse. And if I will create image with this "Is Library" project the latest will no resolving. Any idea?
Yes, you can use the same JNI signature in many applications. Your class may not belong to the default package of the application, as defined in AndroidManifest.xml. So what?
Example:
Start with HelloJni sample from NDK (in Eclipse, use Import -> Android -> existing Android Code, and point to the ${android-ndk-root}/samples/hello-jni).
Build it and run on device or emulator.
Open a new Android Application project, call it TestCrossJni.
The package name for our app will be: test.cross.jni - no relation to com.example.hellojni!
Choose "Create Activity" -> create Blank Activity.
Add new Java class to this project (src/com/example/hellojni/HelloJni.java):
package com.example.hellojni;
public class HelloJni
{
public static String gets() {
return stringFromJNI();
}
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
private native String stringFromJNI();
/* this is used to load the 'hello-jni' library on application
* startup. The library has already been unpacked into
* /data/data/com.example.hellojni/lib/libhello-jni.so at
* installation time by the package manager.
*/
static {
System.load("/data/data/com.example.hellojni/lib/libhello-jni.so");
}
}
Edit res/layout/activity_main.xml: replace
line 12 android:text="#string/hello_world" />
with android:id="#+id/hello_world" />
In src/test/cross/jni/MainActivity.java, add the following after
line 12 setContentView(R.layout.activity_main);
((android.widget.TextView)findViewById(R.id.hello_world)).setText(com.example.hellojni.HelloJni.gets());
Profit!
I wonder why there is no proper answer to this question, I searched for couple of hours but no good answer.
So, we work on a team in which my friend wrote a C library and compiled it as a .so file (it's called ttplib.so)(assume I don't have access to it's C code). Now I have to use that .so file in my android application. But I don't know how to load the library and how to use its methods. I have good documentation of it.
That would be great if you can tell me how to create the Android.mk file too.
Do I have to use dlopen?
Put ttplib.so in the new project's libs/armeabi or libs/armeabi-v7a folder depending what it was compiled with.
Somewhere in your new app (before interacting with the library) add this line of code
System.loadLibrary( "ttplib" );
Now that it's loaded in memory, you'll need to interact with it using JNI. You'll have to go back to the C code to export some JNI functions:
JNIEXPORT jint JNICALL Java_com_example_package_MyClass_methodName( JNIEnv* env, jobject jthis, jfloat value )
{
return 5;
}
Then you'll need to add ClassName.java in your new project:
package com.example.package;
public class MyClass
{
private native int methodName( float value );
private void someJavaMethod()
{
int i = methodName( 65.33f );
}
}
That's it, in a nutshell.