• A-Fu Design
  • 前端設計
    • jQuery 套件
    • HTML 5
  • 關於A-Fu
  • 隱私權政策
  • 聯絡A-Fu
Google+ facebook twitter

A-Fu Design

A-Fu Design

Facebook Open Source React Native


刪除默認權限

默認情況下,您的 Android APK 會添加一些權限。

添加的默認權限是:
  • android.permission.INTERNET - 調試模式所必需的。
  • android.permission.SYSTEM_ALERT_WINDOW - 調試模式所必需的。
  • android.permission.READ_PHONE_STATE - 調試或生產不需要。
  • android.permission.WRITE_EXTERNAL_STORAGE - 調試或生產不需要。
  • android.permission.READ_EXTERNAL_STORAGE - 調試或生產不需要。
  1. 讓我們從生產和調試 APK 中刪除 READ_PHONE_STATE,WRITE_EXTERNAL_STORAGE 和 READ_EXTERNAL_STORAGE 開始,因為它們中都不需要。如果正在使用 AsyncStorage 模塊,則仍然不需要這些存儲權限,因此可以安全地從生產和調試中刪除。
  2. 打開你的 android/app/src/main/AndroidManifest.xml 文件.
  3. 即使清單中未列出這三個權限,它們也會被添加。我們使用工具添加三個權限:node =“remove”屬性,以確保在構建期間刪除它們。請注意,包標識符將不同,因為下面是“com.myapp”,因為該項目是使用 react-native init myapp 創建的。
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.myappid"
    +   xmlns:tools="http://schemas.android.com/tools"
        >
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    +   <uses-permission tools:node="remove" android:name="android.permission.READ_PHONE_STATE" />
    +   <uses-permission tools:node="remove" android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    +   <uses-permission tools:node="remove" android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
        <application
          android:name=".MainApplication"
          android:label="@string/app_name"
          android:icon="@mipmap/ic_launcher"
          android:allowBackup="false"
          android:theme="@style/AppTheme">
          <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
          </activity>
          <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
        </application>
    
    </manifest>
    
  4. 現在讓我們從生產APK中刪除 SYSTEM_ALERT_WINDOW
  5. 轉到 android/app/src/ 錄。在此目錄中創建一個名為release的新目錄。 (路徑: android/app/src/release/)
  6. 在這個android/app/src/release/ 目錄裡面創建一個 AndroidManifest.xml 文件. (路徑: android/app/src/release/AndroidManifest.xml)
  7. 在此文件中粘貼以下內容。請注意,請確保將您的包標識符從“com.myapp”更新為您的包標識符。
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.myapp"
        xmlns:tools="http://schemas.android.com/tools">
    
        <uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    
    </manifest>
    
就是這樣。我們沒有刪除INTERNET權限,因為幾乎所有應用都使用它。現在,無論何時創建生產APK,所有這4個權限都將被刪除。當您創建調試APK(react-native run-android)時,它將安裝僅刪除了三個權限的APK,並且SYSTEM_ALERT_WINDOW將保留。



Share
Tweet
Pin
Share
No 意見
Facebook Open Source React Native
生成簽名 APK

Android要求所有應用都必須使用證書進行數字簽名才能安裝,因此要通過Google Play商店分發您的Android應用,您需要生成已簽名的版本APK。 Android開發者文檔上的“簽署您的應用程序”頁面詳細描述了該主題。本指南簡要介紹了該過程,並列出了打包JavaScript包所需的步驟。

生成簽名密鑰


您可以使用keytool生成私有簽名密鑰。在Windows上,必須從 C:\Program Files\Java\jdkx.x.x_x\bin.
$ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
此命令會提示您輸入密鑰庫和密鑰的密碼,並提供密鑰的“可分辨名稱”字段。然後,它將密鑰庫生成為名為 my-release-key.keystore的文件。
密鑰庫包含一個密鑰,有效期為10000天。別名是您稍後在簽署應用時使用的名稱,因此請記住注意別名。

在Mac上,如果你不確定你的jdk bin文件夾在哪裡,那麼執行以下命令來找到它,$ / usr / libexec / java_home它將輸出看起來像這樣的jdk的directroy,/ Library / Java / JavaVirtualMachines / jdk1。 8.0_161.jdk / Contents / Home然後通過以下命令導航到該目錄:$ cd /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home/現在您可以使用sudo權限執行keytool命令,如圖所示下面,$ sudo keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000注意:請記住將密鑰庫文件保密,並且永遠不要將其提交給版本控制。

設置gradle變量

  1. 將 my-release-key.keystore 文件放在項目文件夾中的 android/app 目錄下。
  2. 編輯文件 ~/.gradle/gradle.properties 或 android/gradle.properties 並添加以下內容(用正確的密鑰庫密碼,別名和密鑰密碼替換*****),
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****
這些將成為全局gradle變量,我們稍後可以在gradle配置中使用它來簽署我們的應用程序。
有關保存密鑰庫的注意事項:
在Play商店中發布應用程序後,如果要在任何時候更改簽名密鑰,則需要使用其他程序包名稱重新發布應用程序(丟失所有下載和評級)。所以備份你的密鑰庫,不要忘記密碼。
關於安全性的注意事項:如果您不希望以純文本格式存儲密碼並且運行OSX,則還可以將您的憑據存儲在Keychain Access應用程序中。然後你可以跳過 ~/.gradle/gradle.properties中的最後兩行。

將簽名配置添加到應用程序的gradle配置中

編輯項目文件夾中的文件android/app/build.gradle 並添加簽名配置,

...
android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}
...

生成發布APK

只需在終端中運行以下命令:
$ cd android
$ ./gradlew assembleRelease
會將運行您的應用程序所需的所有JavaScript捆綁到APK中。如果您需要更改捆綁JavaScript包和/或可繪製資源的方式(例如,如果您更改了默認文件/文件夾名稱或項目的一般結構),請查看 android/app/build.gradle 以查看如何更新它以反映這些變化。
注意:確保gradle.properties不包含org.gradle.configureondemand = true,因為這將使發布版本跳過將JS和資產捆綁到APK中。
生成的APK可以在 android/app/build/outputs/apk/app-release.apk下找到,並準備發布。

測試應用的發布版本

在將發布版本上載到Play商店之前,請確保徹底測試。首先卸載已安裝的任何先前版本的應用程序。使用以下方法將其安裝在設備上
$ react-native run-android --variant=release
請注意 --variant=release 僅在您按上述方式設置簽名時才可用。
您可以終止任何正在運行的打包程序實例,所有框架和JavaScript代碼都捆綁在APK的資產中。

由ABI拆分APK以減小文件大小

默認情況下,生成的APK具有x86和ARMv7a CPU架構的本機代碼。這樣可以更輕鬆地共享幾乎在所有Android設備上運行的APK。但是,這有一個缺點,即任何設備上都會有一些未使用的本機代碼,導致不必要的更大的APK。
您可以通過更改 android/app/build.gradle 中的以下行為每個CPU創建一個APK:
- def enableSeparateBuildPerCPUArchitecture = false
+ def enableSeparateBuildPerCPUArchitecture = true
將這些文件上傳到支持設備定位的市場,例如Google Play和Amazon AppStore,用戶將自動獲得相應的APK。如果您要上傳到其他市場,例如APKFiles,它不支持單個應用的多個APK,請更改以下行以創建默認的通用APK,其中包含兩個CPU的二進製文件。
- universalApk false  // If true, also generate a universal APK
+ universalApk true  // If true, also generate a universal APK

啟用Proguard以減小APK的大小(可選)

Proguard是一種可以略微減小APK大小的工具。它通過剝離應用程序未使用的部分React Native Java字節碼(及其依賴項)來實現此目的。

重要提示:如果您啟用了Proguard,請務必徹底測試您的應用。 Proguard通常需要特定於您正在使用的每個本機庫的配置。請參閱 app/proguard-rules.pro.
要啟用Proguard,請編輯android/app/build.gradle:
/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = true

Share
Tweet
Pin
Share
No 意見
Facebook Open Source React Native


Headless JS

Headless JS 是一種在應用程序處於後台時在JavaScript中運行任務的方法。例如,它可用於同步新數據,處理推送通知或播放音樂。

The JS API

任務是在AppRegistry上註冊的簡單異步函數,類似於註冊React應用程序:
AppRegistry.registerHeadlessTask('SomeTaskName', () => require('SomeTaskName'));
然後, 在 SomeTaskName.js:
module.exports = async (taskData) => {
  // do stuff
};
只要不觸及UI,您就可以在任務中執行任何操作:網絡請求,計時器等。一旦您的任務完成(即承諾得到解決),React Native將進入“暫停”模式(除非有其他任務在運行,或者有一個前台應用程序)。

The Java API

是的,這仍然需要一些本機代碼,但它非常薄。您需要擴展 HeadlessJsTaskService 並覆蓋 getTaskConfig,例如:
public class MyTaskService extends HeadlessJsTaskService {

  @Override
  protected @Nullable HeadlessJsTaskConfig getTaskConfig(Intent intent) {
    Bundle extras = intent.getExtras();
    if (extras != null) {
      return new HeadlessJsTaskConfig(
          "SomeTaskName",
          Arguments.fromBundle(extras),
          5000, // timeout for the task
          false // optional: defines whether or not  the task is allowed in foreground. Default is false
        );
    }
    return null;
  }
}
然後將服務添加到 AndroidManifest.xml 文件中:
<service android:name="com.example.MyTaskService" />
現在,無論何時開始提供服務,例如作為一個週期性任務或響應某些系統事件/廣播,JS將啟動,運行您的任務,然後旋轉。
例如:
Intent service = new Intent(getApplicationContext(), MyTaskService.class);
Bundle bundle = new Bundle();

bundle.putString("foo", "bar");
service.putExtras(bundle);

getApplicationContext().startService(service);

注意事項

  • 默認情況下,如果您嘗試在應用程序位於前台時運行任務,您的應用程序將崩潰。這是為了防止開發人員通過在任務中完成大量工作並減慢UI來自我攻擊。您可以傳遞第四個布爾參數來控制此行為。
  • 如果從 BroadcastReceiver 啟動服務,請確保在從 onReceive() 返回之前調用 HeadlessJsTaskService.acquireWakeLockNow()。

示例用法

可以從Java API啟動服務。首先,您需要確定何時應該啟動服務並相應地實施解決方案。這是一個對網絡連接變化做出反應的簡單示例。

以下行顯示了用於註冊廣播接收器的Android清單文件的一部分。
<receiver android:name=".NetworkChangeReceiver" >
  <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
  </intent-filter>
</receiver>
然後,廣播接收器處理在onReceive函數中廣播的意圖。這是一個檢查您的應用是否在前台的好地方。如果應用程序不在前台,我們可以準備啟動的意圖,沒有使用putExtra捆綁的信息或附加信息(請記住,bundle只能處理parcelable值)。最後,服務開始並獲得喚醒鎖。
public class NetworkChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, final Intent intent) {
        /**
          This part will be called everytime network connection is changed
          e.g. Connected -> Not Connected
        **/
        if (!isAppOnForeground((context))) {
            /**
              We will start our service and send extra info about
              network connections
            **/
            boolean hasInternet = isNetworkAvailable(context);
            Intent serviceIntent = new Intent(context, MyTaskService.class);
            serviceIntent.putExtra("hasInternet", hasInternet);
            context.startService(serviceIntent);
            HeadlessJsTaskService.acquireWakeLockNow(context);
        }
    }

    private boolean isAppOnForeground(Context context) {
        /**
          We need to check if app is in foreground otherwise the app will crash.
         http://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not
        **/
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses =
        activityManager.getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        final String packageName = context.getPackageName();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance ==
            ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
             appProcess.processName.equals(packageName)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isNetworkAvailable(Context context) {
        ConnectivityManager cm = (ConnectivityManager)
        context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm.getActiveNetworkInfo();
        return (netInfo != null && netInfo.isConnected());
    }


}


Share
Tweet
Pin
Share
No 意見
Older Posts

About me

還在努力掙扎中的工程師

Follow Us

  • Google+
  • facebook
  • twitter

Categories

Accordion Animation AutoComplete CSS Calendar Canvas Carousel Charts Color DatePicker Effects Facebook API Forms Gallery HTML5 Menu Mootools Prototype React images jQuery javascripts lightbox 前端技術 統計圖表 網頁設計

Recent Posts

  • jQuery Gantt Chart 在網頁上繪製甘特圖的 jQuery 套件
  • Kalendae 一個不依賴任何框架的日期選擇器
  • AJAX progress bar 非同步傳輸結合 XML 資料回傳
  • Line Developer Day 2018 內部技術與實務分享
  • NCC資安初級認證?只有這 5 款通過

Sponsor

Facebook

Blog Archive

  • 9月 2025 (26)
  • 8月 2025 (62)
  • 7月 2025 (62)
  • 6月 2025 (58)
  • 4月 2025 (48)
  • 3月 2025 (60)
  • 2月 2025 (51)
  • 1月 2025 (56)
  • 12月 2024 (61)
  • 11月 2024 (60)
  • 10月 2024 (54)
  • 9月 2024 (55)
  • 8月 2024 (42)
  • 7月 2024 (40)
  • 6月 2024 (19)
  • 9月 2023 (3)
  • 4月 2023 (2)
  • 2月 2023 (1)
  • 12月 2021 (1)
  • 1月 2019 (11)
  • 12月 2018 (31)
  • 11月 2018 (31)
  • 10月 2018 (31)
  • 9月 2018 (30)
  • 8月 2018 (31)
  • 7月 2018 (3)
  • 2月 2018 (1)
  • 4月 2015 (1)
  • 9月 2014 (1)
  • 2月 2014 (1)
  • 7月 2013 (1)
  • 2月 2013 (2)
  • 1月 2013 (1)
  • 12月 2012 (12)
  • 11月 2012 (81)
  • 10月 2012 (64)

Created with by ThemeXpose | Distributed by Blogger Templates