I have two APKs. First APK is a main APK which loads second APK.
MainActivity.java (first APK): Object mainFragment
was loaded by DexClassLoader early
setContentView(R.layout.activity_main);
LinearLayout fragContainer = findViewById(R.id.main_fragment);
LinearLayout ll = new LinearLayout(context);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setId(View.generateViewId());
getSupportFragmentManager().beginTransaction().add(ll.getId(), mainFragment, "mainFragment").commit();
fragContainer.addView(ll);
activity_main.xml (first APK):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="@+id/main_fragment"
android:orientation="vertical"
/>
</LinearLayout>
MainFragment.java (second APK):
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
fragment_main.xml (second APK):
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="@string/sign_in"
android:layout_width="88dp"
android:layout_height="wrap_content"
android:id="@+id/emailSignInButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="32dp"
android:layout_marginEnd="32dp" android:layout_marginTop="8dp"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
I don't understand, why in the line
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view
is always NULL. Do I need to load R.layout.fragment_main
into memory like mainFragment
?
@CommonsWare already answered you: you are loading classes, not resources.
In Android´s packages, you have both classes (Like R), and resources (Preprocessed XML files, like layouts, for example). A ClassLoader is capable of reading and loading the first ones, so, loading another´s APK R class is possible. But R´s indexes just point towards resource files, they don´t contain the actual values of said resources. So, the R class you sideloaded does not provide the route to a valid resource. If R could do that, then the APK/AAR/APKLib formats would not exists; regular JAR files would suffice. But they don`t,because android resource files are different from class files, and thus, a "link" of sorts is necessary to make them visible to your classes: the R class.
if you want to make your current code work, you need to replace fragment_main.xml with a coded viewgroup instance. Create a class/method providing a constraintLayout instance housing your button (MyViewFactory.createConstraintLayoutWithButton, for example), set the properties via code, and replace
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, viewGroup, false);
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
with something like
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = MyViewFactory.createConstraintLayoutWithButton(getContext)
view.findViewById(R.id.emailSignInButton).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
return view;
}
As long as you don´t use resources, you´ll be fine. That said, this approach is quite fragile, so maybe it would be better to create intent filters between your APKs in order to make APK 2 to work for APK 1.
Edit: You can use the R constants as ids for your code generated views, as long as you set them manually first. For example:
public static ConstraintLayout createConstraintLayoutWithButton(Context context){
Constraintlayout mylayout = new ConstraintLayout(context);
//set up of the layout
Button myButton = new Button(context);
//set up of the button
button.setId(R.id.emailSignInButton);
myLayout.addView(button);
return mylayout;
}
And then you can locate that button with the id.