The following adaptations are for mixed-development projects using MUI and H5 + apis and native code implementations


I recently took on a company project that was old and hadn’t been adapted since Android 5.0, but there wasn’t enough time to rewrite it, and my climb into the pit began. (The following adaptation schemes are in the order of project requirements)

The camera part

Adaptation, certainly step by step, from Android 6.0 to adapt it. Was a colleague said feedback h5 call native camera when a dark, after debugging found is authority was refused, and then I gave him the application of the management in the open, the camera can be normal call, however I found in the testing process, application of new installation bug will recur, later found no add authority to apply for this function, A bit of a surprise, I have to say. All right, let’s get down to business. To recap, the biggest change to 6.0 is a new feature – the addition of permission management. Starting with 6.0 (API 23), users began to grant permissions to applications while they were running, rather than when they were installed. This permission mechanism enables users to better manage application permissions and protect user privacy. Android divides permissions into common permissions and dangerous permissions. Users need to manually allow dangerous permissions. There are 9 groups of 24 dangerous permissions, including calling, camera, location and so on. The following is a table of permissions for your reference. Refer to a more detailed list of permissions

Danger Permission List
Permissions group name Permission to name
CALENDAR READ_CALENDAR, WRITE_CALENDAR
CAMERA CAMERA
CONTACTS READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE, CALL_PHONE, READ_CALL_LOG, WRITE_CALL_LOG, ADD_VOICEMAIL, USE_SIP, PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE

Our project uses the framework of MUI, and the camera part is realized by native code, so the adaptation of this requires the H5 + API provided by Dcloud to attach official documentation

Or post the following code, some of the more lazy partners need not check
var Context = plus.android.runtimeMainActivity();
var res = plus.android.invoke("android.support.v4.app.ActivityCompat"."checkSelfPermission", Context, "android.permission.CAMERA");
var PERMISSIONS_STORAGE = new Array();
PERMISSIONS_STORAGE.push("android.permission.CAMERA");
if(res ! ="0") {
  plus.android.invoke("android.support.v4.app.ActivityCompat"."requestPermissions", Context, PERMISSIONS_STORAGE, 1);
}
plus.scanplug.GetScanCodeFunction(function(result) {}, function(result) {});
Copy the code
Later, some friends said that due to the migration to Android X, this method can not be used, in fact, just need to change the corresponding class name on the line, the above code part needs to be synchronized adaptation, the same post source code

For details on the mapping, check out the official documentation (friendly tip: science online) developer.android.com

var Context = plus.android.runtimeMainActivity();
var res = plus.android.invoke("androidx.core.app.ActivityCompat"."checkSelfPermission", Context, "android.permission.CAMERA");
var PERMISSIONS_STORAGE = new Array();
PERMISSIONS_STORAGE.push("android.permission.CAMERA");
if(res ! ="0") {
  plus.android.invoke("androidx.core.app.ActivityCompat"."requestPermissions", Context, PERMISSIONS_STORAGE, 1);
}
plus.scanplug.GetScanCodeFunction(function(result) {}, function(result) {});
Copy the code

The above is the corresponding adaptation made in THE JS of MUI. In order to better compatibility, permissions need to be handled accordingly in the native code. There was no management of this part in the project originally, but I packaged one in the most primitive way by myself. The easiest to get started, the easiest to use. Again, post the address RxPermissions first. Although it hasn’t been updated for more than a year, the permissions part still works. Changes will need to be made for Android 10, which will be covered later.

You only need to configure the following dependencies in module build.gradle to reference them successfully

implementation 'com. Tbruyelle. Rxpermissions: rxpermissions: 0.7.0'
Copy the code

This is then implemented where it needs to be called

if (Build.VERSION.SDK_INT > 23){
    RxPermissions.getInstance(mContext)
            .request(Manifest.permission.CAMERA)
            .subscribe(new Action1<Boolean>() {
                @Override
                public void call(Boolean granted) {
                    if(granted){// Implementation code}}}); }else{// This shows that the system version is under 6.0, do not need to dynamically obtain permissions // the actual implementation of the function of the code}Copy the code

In this way, with the double guarantee, there should be no problem with the permission of the camera, because there are limited devices on hand. If you have any problems in use, please leave a message or send me a private message, I will try my best to solve them.

Android O (8.0) Upgrade automatic installation problem

After the permission adaptation of the camera, the project was finally online. Before, I was forced to go to Liangshan because of the permission problem of the camera, and I looked through numerous documents, but it was solved. After the launch, in an update, some users reported that they could not install the application and were prompted to upgrade immediately. After downloading the installation package, the system would blink back or still stay on the upgrade page. Online search cannot upgrade automatically, all 8.0 later installed automatically limited, in the later tests, found that is more than 8.0 devices will appear this problem, the solution is very simple, need only in AndroidManifest. Add the following this sentence in the XML

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
Copy the code

If still not solved, you can add the following sentence

<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
Copy the code

If you are more careful, you need to remind whether to enable the installation permission of unknown sources, but fortunately, many device manufacturers have done this in the bottom of the processing, here is temporarily ignored, the spirit of exploration can try.

PS: Say more. A lot of people responded to me saying that this is the most basic way to develop Android, and it bothers me too. I here, because of the company’s business development, front end are almost all h5, number of pages, such as the public or is a small program, do less, and understanding of this part android from can also be a cautionary tale, remind everybody to do friends, don’t forget your bank skills, give people reason to laugh at you.

Network request section

This was found in the internal test. Even my colleague’s mobile phone could not request the network after the package was installed. They once thought the package I sent was a test package, HAH. At the beginning, I was also very confused. I searched for a lot of keywords to find the answer, but there was no result. Finally, I found that all my colleagues whose devices could not access the data were Android P (9.0). The most direct way to solve the problem is to pass it on to the backend colleagues. Since 9.0, Google has banned cleartext data transfer, so simply replace HTTP requests with HTTPS. But if the back end is bad or uncooperative, you can only use internal work. 1) targetSdkVersion below 27 2) The simplest way to do this is to add the following statement to the androidmanifest.xml

android:usesCleartextTraffic="true"
Copy the code

PS: Update, many friends say that adding this sentence does not work. After testing, gradle version 3.2.0 and later version can be used normally. As for the reasons, I won’t go too far. Interested can try, solved can give me a message ha.

3) Change the network security configuration. ① Create an XML folder in the RES folder, and then create a network_security_config. XML file

<? xml version="1.0" encoding="utf-8"? > <network-security-config> <base-config cleartextTrafficPermitted="true" />
</network-security-config>
Copy the code

② Next, add the following attributes to the application tag in the androidmanifest.xml file

android:networkSecurityConfig="@xml/network_security_config"
Copy the code

I used the second option in my project, so let’s mix it up and get what we need.

Android N (7.0) permissions shrink, making it harder to apply for permissions

Recently, two colleagues changed their phones, one is OnePlus 7T and the other is Huawei Meta 30, both of which are manufactured with Android Q (10). A problem was found on these two phones, that is, the same problem occurred in automatic update as in adaptation of Android 8.0. Repeated search and debugging were conducted. No solution was found. The previous update is using H5 + API implementation, forced by this is a third party framework, after the forum to seek a solution to the fruitless, determined to upgrade this piece of native implementation, and then to my Android 10 adaptation journey, as for why the sub-title is Android 7.0 adaptation, please be patient to see below. My first step was to directly look for the encapsulated implementation scheme on the Internet. After searching for a long time, I wrote a demo and found it usable, simple, convenient and interactive. I was excited to think that such a good thing could be integrated into my project, so I started to prepare. The next step is to climb the pit journey, the detailed steps are in accordance with this simple book operation, but the author may only paste the most critical update implementation code. I won’t go into this part of the upgrade process, just mention the problems I encountered during the integration. The first step after integration, happily click the green Run button in Studio, and then the installation package starts to download puPU, the notification bar is also very compatible with the progress of loading, and then… And then… And then after downloading, there was an error during installation. I was surprised that there was an error after integration in demo. So I started to debug it –debug it and see the error. Tip is

FileUriExposedException
Copy the code

The apK installation package is not in the directory of the package name, so there is no permission to obtain the apK installation operation, so there is no way to call the operation. After Android 7.0, you will need to use the FileProvider method to gain temporary access to external folders. Here is also a good article that addresses this issue. Android 7.0 because of the file:// caused by the FileUriExposedException exception, this article introduction is very detailed, including later caused what error, and then how to resolve all have a description. In simple terms, you can configure a provider component in androidmanifest.xml, which is used to apply for a temporary access to the external path, and then configure a path to the directory you need to access, so that you can access the directory and protect user privacy.

 <provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.xg.shfcoc.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
Copy the code

Create a new XML folder in the RES directory and create a file with the same name as the one configured in the provider. The file name I created was file_paths.

<? xml version="1.0" encoding="utf-8"? > <paths > <external-files-path name="external-files-path" path="VersionChecker/"/>

</paths>
Copy the code

< Paths allows you to define sub-nodes

Child nodes Corresponding path example
files-path Context.getFilesDir()
cache-path Context.getCacheDir()
external-path Environment.getExternalStorageDirectory() /storage/emulated/0/
external-files-path Context.getExternalFilesDir(null)
external-cache-path Context.getExternalCacheDir()

More specific words is the following explanation

1.<root-path/> indicates the root directory of the device. New File("/"); <files-path/> represents context.getfilesdir () 3.<cache-path/> represents context.getcachedir () 4.<external-path/> On behalf of the Environment. External.getexternalstoragedirectory () 5. < external files - path > is for context. GetExternalFilesDirs () 6. < external cache - path > representative getExternalCacheDirs ()Copy the code

The name attribute is used to alias the subdirectory name specified by the path attribute. This alias is used instead of the real directory name when content:// URI is generated later. The path attribute is used to specify the name of the subdirectory to be shared under the directory represented by the current child element. Note: The path attribute value cannot use a specific individual file name, only a directory name.

No more will not say, it is still do not understand, this paper and the major search engines to achieve strategic cooperation, can search results.

If I want to replace the directory is/storage/emulated / 0 / diary sdcard/photo/configuration should be written

<? xml version="1.0" encoding="utf-8"? > <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="VersionChecker"/>
</paths>
Copy the code
In particular, my directory configuration is this, later on Android 10 will appear flash back phenomenon, so I changed to this configuration, the reason is unknown, but this can solve the problem, there is no more trouble, can solve the problem is the most important. *

After that, do the following to get the file where you want to store it

getExternalFilesDir("Folder name").getAbsolutePath()+"/"
Copy the code

Then get automatic updates as shown below

Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// System.out.println(result.getPath());
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); Installintent.addflags (intent.flag_grant_read_uri_permission); Uri contentUri = FileProvider.getUriForFile(DownApkService.this, BuildConfig.APPLICATION_ID +".fileProvider", new File(result.getPath()));

    installIntent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
    installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    installIntent.setDataAndType(Uri.fromFile(new File(result.getPath())), "application/vnd.android.package-archive");
}
Copy the code

Intent.setflags (intent.flag_activity_new_task); Must be in installIntent.addflags (intent.flag_grant_read_uri_permission); The previous setting and the previous sentence must be addFlags instead of setFlags, otherwise the package parsing exception will occur on Android 10 devices. By the way, BuildConfig must be a reference to your project’s own package, not another jar’s method, otherwise it will throw exceptions. If you are interested, try it.

I would like to add that the network request framework used in this project is the Xutils, xUtils3 Github portal.

The solution is as follows: simply configure the following dependencies in the Build. gradle module to reference them successfully

implementation 'org. Xutils: xutils: 3.8.3'
Copy the code

Then write an Activity that initializes the Xutils here

@Override
public void onCreate() {
   super.onCreate();

   x.Ext.init(this);
   x.Ext.setDebug(BuildConfig.DEBUG);

}
Copy the code

You can’t have setContentView(r.layout.xxx) in your Activity onCreate() or you’ll get an error.

The initialization above leads to the following question. Because this project uses MUI and native mixed development, the official name of Dcloud is offline packaging. What matters is the usage. Xutils needs to be initialized when it is used, and the general processing method is in Androidmanifest.xml. <application node add android:name=”.ApplicationContext” But our project must such configuration android: name = “IO. Dcloud. Application. DCloudApplication”, to use the mui plus call native methods. So the solution is to post the entire source code here

package com.xxx;

import android.content.Context;
import org.xutils.x;
import io.dcloud.application.DCloudApplication;

public class ApplicationContext extends DCloudApplication {
   private static ApplicationContext context;

   public static ApplicationContext getContext() {return context;
   }

   @Override
   protected void attachBaseContext(Context base) {
       super.attachBaseContext(base);
       context = this;
   }

   @Override
   public void onCreate() { super.onCreate(); x.Ext.init(this); x.Ext.setDebug(BuildConfig.DEBUG); }}Copy the code

Android :name=”.ApplicationContext” This perfectly resolves Xutils references and does not affect muI native calls.

This is the first installment of the adaptation, which will be updated as soon as possible to pick up lost Android skills.