This is default featured slide 1 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 2 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 3 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 4 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

This is default featured slide 5 title

Go to Blogger edit html and find these sentences.Now replace these sentences with your own descriptions.

Showing posts with label tutorial. Show all posts
Showing posts with label tutorial. Show all posts

Friday, 10 April 2020

How can i install Xposed on Nox Android 7.1.2?

How can i install Xposed on Nox  Android 7.1.2?


Lot of people will ask about this problem. Because on Nox android 7.1.2, there is no Xposed installer can install Xposed module. So how can we do that?

To install Xposed, we will need these file:


  1. Xposed SDK Module
  2. Xposed installer 3.15
  3. Terminal Emulator for Android

We do not need to install Super Su. Because Nox will be broken after install Super SU.




After download and install all of the tool above. Follow these steps.


  1.  Extract the Xposed SDK Module and you will get the "xposed" Folder.
  2. Copy this Folder and paste to the /sdcard. 
  3. Run Terminal Emulator. 
  4. Type the command "super su"
  5. Type the command "cd /sdcard/xposed"
  6. Type the command "sh flash-script.sh"
  7. Wait until the process complete. And then reboot Nox.
  8. Run the Xposed installer, and you will see that Xposed module was installed on Nox.


If you still get any problem, just leave a comment here and we will help you.

How many solution to Request permissions in Android Application?

How many solution to Request permissions in Android Application?



Starting from Android 6.0 (API 23), users are not asked for permissions at the time of installation rather developers need to request for the permissions at the run time. Only the permissions that are defined in the manifest file can be requested at run time.
Types of Permissions:



  1. Install-Time Permissions: If the Android 5.1.1 (API 22) or lower, the permission is requested at the installation time at the Google Play Store.
     

    If the user Accepts the permissions, the app is installed. Else the app installation is cancelled.
  2. Run-Time Permissions: If the Android 6 (API 23) or higher, the permission is requested at the run time during the runnnig of the app.






If the user Accepts the permissions, then that feature of the app can be used. Else to use the feature, the app requests the permission again.

So, now the permissions are requested at runtime. In this article, we will discuss how to request permissions in an Android Application at run time.

Steps for Requesting permissions at run time :
  1. Declare the permission in Android Manifest file: In Android permissions are declared in AndroidManifest.xml file using the uses-permission tag.

     <uses-permission android:name=”android.permission.PERMISSION_NAME”/> 
    Here we are declaring storage and camera permission.

    <!--Declaring the required permissions-->
    <uses-permission
    android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
    <uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-permission
    android:name="android.permission.CAMERA" /> 
  2. Modify activity_main.xml file to Add two buttons to request permission on button click:

    Permission will be checked and requested on button click. Open activity_main.xml file and add two buttons in it.



    <!--Button to request storage permission-->
    <Button
    android:id="@+id/storage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Storage"
    android:layout_marginTop="16dp"
    android:padding="8dp"
    android:layout_below="@id/toolbar"
    android:layout_centerHorizontal="true"/> 

    <!--Button to request camera permission-->
    <Button
    android:id="@+id/camera"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Camera"
    android:layout_marginTop="16dp"
    android:padding="8dp"
    android:layout_below="@id/storage"
    android:layout_centerHorizontal="true"/> 
  3. Check whether permission is already granted or not. If permission isn’t already granted, request user for the permission:

    In order to use any service or feature, the permissions are required. Hence we have to ensure that the permissions are given for that. If not, then the permissions are requested.

    Check for permissions:

    Beginning with Android 6.0 (API level 23), the user has the right to revoke permissions from any app at any time, even if the app targets a lower API level. So to use the service, the app needs to check for permissions every time.

    Syntax:


    if(ContextCompat.checkSelfPermission(thisActivity,
    Manifest.permission.WRITE_CALENDAR)
    != PackageManager.PERMISSION_GRANTED)
    {
    // Permission is not granted
    }


    Request Permissions: When PERMISSION_DENIED is returned from the checkSelfPermission()
    method in the above syntax, we need to prompt the user for that
    permission. Android provides several methods that can be used to request
    permission, such as requestPermissions().


    Syntax:




    ActivityCompat.requestPermissions(MainActivity.this,
    permissionArray,
    requestCode);
    Here permissionArray is an array of type String.





    Example:




    // Function to check and request permission public void checkPermission(String permission, int requestCode) {
    // Checking if permission is not granted if (ContextCompat.checkSelfPermission( MainActivity.this, permission) == PackageManager.PERMISSION_DENIED) { ActivityCompat .requestPermissions( MainActivity.this, new String[] { permission }, requestCode); } else { Toast .makeText(MainActivity.this, "Permission already granted", Toast.LENGTH_SHORT) .show(); } }


    This function will show a toast message if permission is already granted otherwise prompt user for permission.


  4. Override onRequestPermissionsResult() method: onRequestPermissionsResult() is called when user grant or decline the permission. RequestCode is one of the parameteres of this function which is used to check user action for corresponding request. Here a toast message is shown indicating the permission and user action.




  5. Example:
    // This function is called when user accept or decline the permission.
    // Request Code is used to check which permission called this function.
    // This request code is provided when user is prompt for permission.
    @Override
    public void onRequestPermissionsResult(int requestCode,
    @NonNull String[] permissions,
    @NonNull int[] grantResults)
    {
    super
    .onRequestPermissionsResult(requestCode,
    permissions,
    grantResults);
    if (requestCode == CAMERA_PERMISSION_CODE) {
    // Checking whether user granted the permission or not.
    if (grantResults.length > 0
    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    // Showing the toast message
    Toast.makeText(MainActivity.this,
    "Camera Permission Granted",
    Toast.LENGTH_SHORT)
    .show();
    }
    else {
    Toast.makeText(MainActivity.this,
    "Camera Permission Denied",
    Toast.LENGTH_SHORT)
    .show();
    }
    }
    else if (requestCode == STORAGE_PERMISSION_CODE) {
    if (grantResults.length > 0
    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    Toast.makeText(MainActivity.this,
    "Storage Permission Granted",
    Toast.LENGTH_SHORT)
    .show();
    }
    else {
    Toast.makeText(MainActivity.this,
    "Storage Permission Denied",
    Toast.LENGTH_SHORT)
    .show();
    }
    }
Below is the complete code of this application:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.geeksforgeeks.requestPermission">
<!--Declaring the required permissions-->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest> 

MainActivity.java

import android.Manifest;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
// Defining Buttons
private Button storage, camera;
// Defining Permission codes.
// We can give any value
// but unique for each permission.
private static final int CAMERA_PERMISSION_CODE = 100;
private static final int STORAGE_PERMISSION_CODE = 101;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
storage = findViewById(R.id.storage);
camera = findViewById(R.id.camera);
// Set Buttons on Click Listeners
storage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
checkPermission(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
STORAGE_PERMISSION_CODE);
}
});
camera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
checkPermission(Manifest.permission.CAMERA,
CAMERA_PERMISSION_CODE);
}
});
}
// Function to check and request permission.
public void checkPermission(String permission, int requestCode)
{
if (ContextCompat.checkSelfPermission(MainActivity.this, permission)
== PackageManager.PERMISSION_DENIED) {
// Requesting the permission
ActivityCompat.requestPermissions(MainActivity.this,
new String[] { permission },
requestCode);
}
else {
Toast.makeText(MainActivity.this,
"Permission already granted",
Toast.LENGTH_SHORT)
.show();
}
}
// This function is called when the user accepts or decline the permission.
// Request Code is used to check which permission called this function.
// This request code is provided when the user is prompt for permission.
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults)
{
super
.onRequestPermissionsResult(requestCode,
permissions,
grantResults);
if (requestCode == CAMERA_PERMISSION_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this,
"Camera Permission Granted",
Toast.LENGTH_SHORT)
.show();
}
else {
Toast.makeText(MainActivity.this,
"Camera Permission Denied",
Toast.LENGTH_SHORT)
.show();
}
}
else if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this,
"Storage Permission Granted",
Toast.LENGTH_SHORT)
.show();
}
else {
Toast.makeText(MainActivity.this,
"Storage Permission Denied",
Toast.LENGTH_SHORT)
.show();
}
}
}
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<!-- To show toolbar-->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:background="@color/colorPrimary"
app:title="GFG | Permission Example"
app:titleTextColor="@android:color/white"
android:layout_height="?android:attr/actionBarSize"/>
<!--Button to request storage permission-->
<Button
android:id="@+id/storage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Storage"
android:layout_marginTop="16dp"
android:padding="8dp"
android:layout_below="@id/toolbar"
android:layout_centerHorizontal="true"/>
<!--Button to request camera permission-->
<Button
android:id="@+id/camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Camera"
android:layout_marginTop="16dp"
android:padding="8dp"
android:layout_below="@id/storage"
android:layout_centerHorizontal="true"/>
</RelativeLayout> 

Monday, 6 April 2020

Mod menu icon disappeared? How to fix it?

Mod menu icon disappeared? How to fix it?



Many days ago, we received lot of information about this problem. You are playing very normally, but 1 day the mod menu icon disappeared.

After investigating, we noticed that the problem is coming from your device. The reason is your Security Center or Antivirus software blocked the permission of Floating Icon. To fix it, run to Security Center. And touch the privacy permission.





In privacy permissions windows, choose Floating windows management.



In Floating Window Management, scroll down to the Applications in floating windows not allowed. Search for your application and turn it on.




Restart your application and check the result.

If you still not how to do it, watch this video below for more details.


Monday, 23 March 2020

IDA Pro: Cross References / Xrefs. How can we deal with it?

IDA Pro: Cross References / Xrefs. How can we deal with it?


Lot of people who are using IDA to debug program, but still not know that how much useful which Cross References can help.

Cross references can help us determine where certain functions were called from, which can be useful for a number of reasons. Let’s say that we found the function we’re interested in for whatever reason: maybe it contains a vulnerable code, we could use to execute malicious shellcode or maybe it does the actual encryption of the data we’re interested in. Once we’ve located the function, we must determine how the program execution leads to the execution of that function. Usually, we would have to set a breakpoint at that function and run the program and let the breakpoint be caught; then we would have to check the previous stack frames to determine which functions were previously called that led to the current function. We would have to backtrace the program execution function by function, manually, which can take a lot of time. But Ida can help us by doing that automatically with the use of cross references.

Cross references show how a particular piece of information was accessed; the information can either be code or data, so that we know code and data cross references. When we talk about code cross references, we’re talking about the location from where certain functions are being called. In addition, we’re talking about the location from where the variable is being accessed.




The cross references are presented in the code disassembly view as can be seen on the picture below:



On the picture above we can see the function at address 0x00436629 that contains the cross reference comment: the CODE XREF. The code references are presented as “CODE XREF”, whereas the data cross references is presented as “DATA XREF”; in our case we can see it’s a code cross reference. The cross reference in our case originates from the address 0x00436608, so the current function is called on that address. We also see the arrow pointing up, which indicates that the function that calls the current function is located upward the disassembly code (has a lower virtual address). After the arrow, there’s also a single letter letting us know what kind of execution transfer was it: a function call, or a conditional/unconditional jump. The letter ‘j’ denotes the jump, while the letter ‘p’ denotes the function call.


Let’s also present the data cross references on the picture below:



We can see that the data cross references are marked with the “DATA XREF” string and use the name and offset if the function is known or virtual address if function is not known to denote the location the data was accessed from. All the data cross references on the picture above have the arrow pointing up, which lets us know that the presented data variables are accessed from the code that has a lower virtual address. Also, the data cross references have different letters assigned after the arrow: the letter ‘w’ denotes that the location is being written to; the letter ‘r’ denotes that the location is being read from, while the letter ‘o’ denotes that the address of the location is being taken from it. On the picture above we can also see three dots (‘…’), which are letting us know that there are other locations in the program that are referencing this location (there are other data cross references as well, but are not displayed). If we would like to display more cross references than just two, we can go to the Options – General – Cross-references and change the “Number of displayed xrefs” from 2 to some other number.



Usually, certain location is referenced quite often and we can’t really display all of the cross references in the comments of the disassembly view because the disassembled code may become hard to read. Let’s take a look at the following data cross reference (shown on the picture below):



We can see that the locations 0x0044A7CE and 0x0044B1ED are referencing the data at the address 0x00474B94, but other cross references also exists (note the three dots ‘…’). Let’s change the “number of displayed xrefs” in the Ida options to 5 and take a look at the cross references again (shown below):



Now there are five different cross references displayed, but there are still more of them hidden. We could change the number of xrefs we would like to be shown at any given time to 10, 20, 30, etc, but that would really make the view look messy. A better way of dealing with this is to point a cursor to the 0x00474B94 line and press on View – Open subviews – Cross references, which will open a list of all cross references to our data variable. That list can be seen on the picture below:



We can see that there are 15 cross references and we’ve just listed them all. We can double-click on any entry above, which will take us to the address of the chosen cross-reference. The first column presents the direction, either up or down, where the cross reference is located. The second column presents whether it’s read, write or pointer cross reference. The third column presents the virtual address where the cross reference is located. And the last column shows the disassembled instruction at the cross reference that references our data variable.


We’ve seen how data cross references can be presented, but what about function. If we would like to know which function calls the current function in which we’re located we can click on View – Open subviews – function calls. An example can be seen below:



The picture displays the virtual addresses that call the current function in which we’re located. There’s only one function that calls the current function and it’s located at 0x0042733B. On the lower part of the window are the functions that are being called by this function. We’ve just seen how the functions are related to one another, which can be a great help when trying to reverse engineer certain programs.


There are a number of graphs we can use displaying the cross references and other information about the currently executed program. If we click on the View – Graphs – Flow charts we will display the current functions building blocks, which are the blocks that will be executed as a whole upon entering the first instruction within each block. An example of a flow chart of the sub_4025DB function can be seen below:



We can see that the current function has quite a lot of building blocks. Let’s present the top three building blocks of the graph above:





We can see that each block only contains the instructions that don’t jump around the program, so whenever a jump (either conditional or unconditional) is made, a new building block needs to be introduced. The graph also presents the jumps between the building blocks, which can be of valuable help. We’ve just seen how a certain function can be divided onto several building blocks, which can be used to present the jump instructions inside a specific function.


Besides the above graph that presented the building blocks of the function, we can also display the graph of all the functions inside the executable. We can do that by pressing the View – Graphs – Function calls option. The function calls of the entire Meterpreter executable can be seen on the picture below:



We can’t really read what’s being written in the nodes, but let’s focus on the colors for now. The purple color is used for the library functions, which can quickly become evident if we zoom the first part of the image, which is shown below:



Did you notice that all of the above function names are actually library functions? The green color is used to denote the entry point of the executable as seen below:



All the black nodes are the sub functions present in the executable itself. Usually there are too many nodes and connections between the nodes to make this graph useful, so it’s not used most of the time. The other reason that it’s not used is that we can only zoom in or out in the program, which can be very tedious if the graph is quite large, not to mention that we can’t search for specific functions.


We’ve already talked about how Ida can help us determine which function calls the current function and which functions are called by the current function. We haven’t yet mentioned that we can also generate a graph by using the cross references to generate the graphs. First of all, we should currently be located on a function that contains at least one cross reference as follows:



We can see that the address 0x004068C8 (which is inside the current function 0x00406811) contains a cross references 0x00406811 which contains one of the jump instructions. Basically, we’re looking at some virtual address of the current location and the cross reference is actually the current function we’re located in. To display a graph of all functions that called the current function recursively up to the entry point of the program we can click on the View – Graphs – Xrefs, which will open the following window:



We can see that the blue circled node presents the function we’re currently in and all the other nodes present the graph of how the program execution reached the function.


We can also create a graph of the functions that are called by the current function by selecting View – Graphs – Xrefs from, which will open the window on the picture below:



We can see that we’re starting from the current function at address 0x00406811 and displaying all the other functions that get called from this function.


The Xrefs to/from have the same problem as the function graphs: they can only be zoomed in and out, which isn’t enough if we’re dealing with a very complex program that has thousands of nodes and even more connections between them. This is why Ida has another graph that can be accessed by selecting View – Graphs – User xrefs chart, which we can interact with in various ways. This graph can show Xrefs ‘to’ and Xrefs ‘from’ graphs joined into one, and additionally it can be instructed to only show only part of the total graph, which can be quite handy when dealing with large graphs. The preferences for this graph are presented on the picture below:



On the picture above we can see that the start and end address are equal, which means that the graph will present all of the Xrefs to and Xrefs from in the currently chosen function. If this isn’t the case, the presented graph will only contain references in the currently selected range. There are also a number of parameters we can choose when generating the graph we want. The “cross references to” and “cross references from” options instruct Ida to search for symbols leading to the current function and leading from the current function, which we’ve already seen. The “recursive” option enables the Ida to recursively check for the symbols to/from the currently selected function. The “follow only current direction” option will only add nodes that can be accessible by the currently selected function and not by the other functions that are found along the way. The “recursion depth” specifies the size of the graph that we would like to generate; the number -1 means the Ida will not be limited and will display all nodes if appropriate.

The “ignore” option specifies what nodes we would like to exclude from the resulting graph. The options are: externals, data, from library functions, to library functions. We can select any of the four types that we wouldn’t like to include on the resulting graph, which can lead to a much simpler graph that is easier to look at. The printing options are used to instruct whether the comments are included into each node if the function has comments in the disassembled view and if a special dots ‘…’ nodes are printed whenever a node has more cross referenced that won’t be followed because of the recursion restriction.


If we display the new graph with the default options, we would receive a graph similar to the one below:



Notice that the graph is the same as if we would join the previously generated Xrefs to and Xrefs from graphs? The graph is quite simple, since the executable is very small, so we don’t really need the “user xrefs chart” graph, because the default Xrefs to and Xrefs from graphs are enough. But let’s present various options from the “user xrefs chart” to better understand them.


If we disable the recursive option we will get the following graph, which only prints the directly accessible nodes from the current node sub_406811. We can see that the xrefs to/from was not recursively checked, which means that only direct ancestors and descendants are visible.



If we disable the “follow only current direction” to include all the parents/children of the found nodes, we’ll receive the graph presented below. We can see that the graph is totally unreadable since all the symbols were included in the graph. This gets us thinking that we really keep the “follow only current direction” option enabled at all times.



If we enter the number 1 into the recursion field, we will receive the graph presented below, since we limited Ida to only recourse once:





If we ignore the Data and Externals, the generated graph will look something like this (the purple nodes will be hidden):


Conclusion

In the article we’ve looked at cross references that are a valuable resource when we want to figure out exactly where the function was called from and what functions the current function calls. This can be quite useful, so we don’t have to traverse the stack for frame pointers to look for the function that called the current function; this is already available in Ida for free, so there is no need to do it manually.

References


[1] Chris Eagle, The IDA Pro Book: The unofficial guide to the world’s most popular disassembler.

Thursday, 19 March 2020

How to deal with the error "unfortunately google play store has stopped"?

How to deal with the error "unfortunately google play store has stopped"?


Some time when using android device, or emulator you may get the error "Unfortunately google play store has stopped".
So how to fix this problem? Now i will tell you the simple way to fix it.

1. Go to Setting, choose Apps.
2. At the Apps list, choose "Google Play Store"



You will see this screen. Choose "Force Stop". Then, choose Uninstall Updates. For some case, you need to choose "Clear Data"






Now, run your Google Play Store again. And maybe you will be asked to re-log in to your account. The problem was solved.



How can i install & update binary Super SU to latest version?

How can i install & update binary Super SU to latest version?



When you root your device or using root on Nox or emulator, maybe you will get the error that


"SU binary needs to be updated."

But you cannot update it to latest version. Here is tutorial for you to update Binary and Super Su to latest version.




First, you need to download these files. From the folder, i attached 2 version of Super Su.

After downloaded, you need to install "supersu_v2.65-265.apk"



After installing it, just run Super Su and you will get this Pop up



Choose Continue, and then Choose Normal.





If this is the 1st time you install on Nox or Menu, you will see this screen.


Just choose "Remember choice forever", and then Allow. You will see this screen. 


Just wait for a seconds, you will receive the message "Successful"


Choose OK. Then install "SuperSU_v2.82.apk" and Run. You will see the same screenshot which require to update Su Binary.


Repeat, and after update successfully, Just reboot your Nox or Menu player. Here is the result.


Wednesday, 11 March 2020

How can i install Split APK?

How can i install Split APK?


Sometimes maybe you will see the application with many files. So how can we install them? They were called split apks.



In order to install them, we need an application with name "SAI" (Split APKs Installer). So:

What is Split APKs Installer?

SAI (Split APKs Installer) is an App that lets you install multiple APKs as if it was a single Package.





This is useful for installing Apps that are distributed as App Bundles since Android provides no built-in way to install them from Sources other than Google Play

Which files extension SAI supports?

*.apk, *.zip

How to install?

You can download SAI from github

From the main application, choose "install apk"


Then, choose all files which you downloaded, or you maybe downloaded a zip file which contains all of files inside. 


Then choose Select. The application will run the installation. If you have not ever run the SAI, you will see the pop up screen like this


Choose Allow.

If successful, you will see the notice that the game or application has been installed.






Congratulation, you have just installed the game successful.

Note:

If you got any problem when installing application by using SAI, please try to enable the Option "Extract APKs from archives", and then try again.



Changelog:

v2.8
• Fixed critical Shizuku and Rooted installers vulnerability
• Updated ukrainian localization @Displax)

v2.7
• Fix problem with illegal characters in exported .apks file name

v2.6
• Option to select which split APK parts to export
• Option to select files to install via system file picker (long click install button)
• Setting to select exported .apks file name format
• New dark theme
• Updated ukrainian localization (@MrIkso & @Displax)

v2.5
• Added Shizuku installer (If you had rooted installer enabled, you have to enable it again in this update)
• Added apps' icons in export fragment
• Added licenses
• Added turkish translation (@FatihFIRINCI)
• Revised exported .apks files naming again
• Updated ukrainian translation (@MrIkso)
• Updated chinese translation (@yaxisvip)

v2.4
• Fixed rooted installer compatibility with some devices (again)

v2.3
• Added option to export all apps that consist of split APKs
• Revised exported apps naming
• Updated chinese localization (@yaxisvip)





v2.2
• Fixed rooted installer compatibility with some devices
• Updated ukrainian translation (@MrIkso)

v2.1
• Fixed an issue which caused app to crash when opening .apks via SAI

v2.0
• Added APK export feature (Beta)

v1.28
• SAI now lets system decide install location (previously internal-only)

v1.27
• Improved stability
• Updated file selection design
• Supports up to 5 dots in the name of the .apks file
• Added F-Droid theme

v1.26
• Stability improvements
• Updated chinese translation and added traditional chinese translation (@yaxisvip)
• Updated ukrainian translation

v1.25
• MIUI crash fix
• Navbar coloring on 8.1+

v1.24
• Improved signing (Now implements zipalign and native libs page-align, file entries in a signed APK inherit compression method from the original APK)
• Updated ukrainian translation

v1.23
• Added option to extract APKs from archives (.zip/.apks) before installing them. This is a workaround for some users who are having problems with rooted installation from archives. Don’t use it if rooted-installer works fine for you, it will only slow down installation. Rootless installer isn’t affected by that problem, so using this feature with it is super not recommended, since it will only slow down installation as well. Basically just don’t use it if installation works fine for you

v1.22
• .zip/.apks archives are now allowed to contain non-apk files, SAI will just ignore them
• Added copy option to error log dialog
• Added one-time warning when using SAI on MIUI

v1.21
• Partial chinese translation by @yaxisvip

v1.20
• Updated file picker design
• Added device info to rooted installer failure log
• Some other minor fixes

v1.19
• Improved buttons on the installation screen
• Added some new themes