我正在尝试生成已签名的APK。我的密码.keystore文件位于\ Dictionary \ android \ app中,当我在cmd上运行gradlew assembleRelease
时,错误:
任务执行失败':app:validateSigningRelease'。
未设置签名配置版本的密钥库文件
我应该在哪里存储我的password.keystore文件?因为当我评论if (project.hasProperty("password.keystore") {
它似乎工作但是反而出现以下错误:
无法处理传入的事件' ProgressComplete' (ProgressCompleteEvent)
我应该如何编写if条件或应该在哪里存储password.keystore文件?
源代码如下:
signingConfigs {
release {
if (project.hasProperty("password.keystore")) {
storeFile file("password.keystore")
storePassword "password"
keyAlias "username"
keyPassword "password"
}
}
}
答案 0 :(得分:16)
密钥库文件必须位于 android / app 文件夹中。
消息'未设置签名配置版本的密钥库文件'必须这样做,android / app / build.gradle文件中没有signedConfig。
buildTypes {
release {
// other settings
signingConfig signingConfigs.release
}
}
对于测试,你可以硬编码android / app / build.gradle中的设置,而不是在gradle.properties中设置它。这给我解决了'Keystore被篡改或密码错误的问题'
signingConfigs {
release {
//if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file("key.keystore")
storePassword "****"
keyAlias "myKey"
keyPassword "****"
// }
}
}
答案 1 :(得分:4)
我找到了解决方法!
如果您像我一样跟随React Native's official instructions,则将关注添加到gradle.properties
MYAPP_RELEASE_STORE_FILE=<your-app>.keystore
MYAPP_RELEASE_KEY_ALIAS=<keystore-alias>
MYAPP_RELEASE_STORE_PASSWORD=<password>
MYAPP_RELEASE_KEY_PASSWORD=<password>
然后是我完全误会的部分。
在app/build.gradle
文件中,不应该替换字符串。如果您的gradle.properties
与我粘贴的app/build.gradle
类似,则您的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
}
}
}
应该如下所示:
gradle.properties
我最初所做的是替换字符串(即'MYAPP_RELEASE_STORE_FILE'与我的密钥库文件的路径),但是不应该完全替换任何变量。我想您可能会看到我们在app/build.gradle
中创建的字符串与我们在.keystore
中创建的release-config之间的联系。
请记住,您的android/app
文件也应放在const path = require('path');
const precss = require('precss');
const webpack = require('webpack');
const packageJson = require('./package.json');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const filenames = {
css: '[name].bundle.css',
js: '[name].bundle.js',
};
console.log('#########################################');
/* Cache busted names for production */
if (process.env.NODE_ENV === 'production') {
console.log('# XXXXXX v', packageJson.version, ' PRODUCTION #');
const timestamp = +new Date();
filenames.css = `[name].bundle.${timestamp}.css`;
filenames.js = `[name].bundle.${timestamp}.js`;
} else {
console.log('# XXXXXX v', packageJson.version, ' DEVELOPMENT #');
}
console.log('#########################################');
console.log('');
module.exports = (env, options) => ({
entry: './src/assets/js/Scheduler.jsx',
output: {
publicPath: '/',
filename: `assets/js/${filenames.js}`,
path: path.resolve(__dirname, 'public'),
},
watchOptions: {
ignored: /node_modules/,
},
node: {
fs: 'empty',
},
devtool: (options.mode === 'production') ? 'source-map' : 'cheap-module-source-map',
devServer: {
hot: true,
watchContentBase: true,
historyApiFallback: true,
contentBase: path.join(__dirname, 'src'),
},
module: {
rules: [{
test: /\.(js|jsx)$/,
exclude: /node_modules|bower_components/,
use: [
'babel-loader',
'eslint-loader',
],
}, {
test: /\.(css)$/,
exclude: /node_modules|bower_components/,
use: [
MiniCssExtractPlugin.loader,
{
/* Interprets `@import` and `url()` like `import/require()` and will resolve them */
loader: 'css-loader',
options: {
sourceMap: true,
},
},
],
}, {
test: /\.(scss)$/,
exclude: /node_modules|bower_components/,
use: [
{
loader: 'css-hot-loader',
options: {
sourceMap: true,
},
},
/**
* Commented out as we want to extract the styles into a seperate file which the mini CSS extract plugin will do.
* If you want to keep the styles within the scripts, comment this back in and comment out mini CSS extract plugin line below.
*/
/*
{
loader: 'style-loader',
options: {
sourceMap: true,
},
},
*/
MiniCssExtractPlugin.loader,
{
/* Interprets `@import` and `url()` like `import/require()` and will resolve them */
loader: 'css-loader',
options: {
sourceMap: true,
},
}, {
/* Loader for webpack to process CSS with PostCSS */
loader: 'postcss-loader',
options: {
autoprefixer: {
browsers: ['last 3 versions'],
},
plugins: loader => [
precss(),
autoprefixer(),
],
sourceMap: true,
},
}, {
/* Loads a SASS/SCSS file and compiles it to CSS */
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
}, {
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
exclude: /node_modules|bower_components/,
use: 'url-loader?limit=10000',
}, {
test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
exclude: /node_modules|bower_components/,
use: 'file-loader',
}, {
test: /\.(png|jp(e*)g|svg|gif)$/,
exclude: /node_modules|bower_components/,
use: [{
loader: 'url-loader',
options: {
limit: 8000, /* Convert images < 8kb to base64 strings */
name: 'assets/img/[name]-[hash].[ext]',
},
}],
}, {
test: /\.html$/,
exclude: /node_modules|bower_components/,
use: {
loader: 'html-loader',
options: {
minimize: true,
},
},
}, {
test: /bootstrap\/dist\/js\/umd\//,
use: 'imports-loader?jQuery=jquery',
}],
},
resolve: {
extensions: ['*', '.jsx', '.js', '.scss', '.css', '.html'],
},
performance: {
hints: false,
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
commons: {
name: 'vendors',
chunks: 'initial',
test: /node_modules/,
},
},
},
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true,
}),
new OptimizeCSSAssetsPlugin(),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: `assets/css/${filenames.css}`,
}),
new HtmlWebPackPlugin({
template: 'src/index.html',
filename: 'index.html',
hash: (options.mode === 'production'),
}),
new HtmlWebPackPlugin({
template: 'src/404.html',
filename: '404.html',
hash: (options.mode === 'production'),
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
}),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([
{
force: true,
cache: true,
to: 'assets/icons',
from: 'src/assets/icons',
}, {
force: true,
cache: true,
to: 'assets/img',
from: 'src/assets/img',
}, {
force: true,
cache: true,
to: 'assets/fonts',
from: 'src/assets/fonts',
}, {
force: true,
cache: true,
to: 'assets/fonts',
from: 'node_modules/font-awesome/fonts',
},
]),
],
});
中。
答案 2 :(得分:3)
我有完全相同的问题。结果我忘了编辑gradle.properties文件。它应该是这样的:
android.useDeprecatedNdk=true
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
答案 3 :(得分:3)
就我而言,我的项目使用的是RN版本0.59,而我使用的是0.60 RC文档。所以在app/build.gradle
如果版本为0.59:
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
如果版本为0.60:
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
区别是从RELEASE
到UPLOAD
答案 4 :(得分:1)
project.hasProperty
将在gradle.properties
文件中查找名为password.keystore的变量。
进入~/.gradle
并查看您是否有gradle.properties
文件,如果有,请确保变量password.keystore
在那里,它应指向您的密钥库文件:{{1 }}
虽然您应该将其命名为不同的内容,例如password.keystore=password.keystore
。然后当你运行MYAPP_RELEASE_STORE_FILE=password.keystore
时,你的项目将拥有它正在寻找的属性,以下将解析为true并允许gradlew设置所有的signedConfigs.release属性:
./gradlew assembleRelease
答案 5 :(得分:1)
在探索了有关此问题的所有答案之后,答案都没有帮助!
在下面的实验中试过,它有助于!!!!
将my-release-key.keystore
文件放在项目文件夹中的 android 目录下。
答案 6 :(得分:1)
我实际上更喜欢使用环境变量将这些参数存储在app repo之外,因为它包含密码等敏感信息。
signingConfigs {
release {
if (System.env.MYAPP_RELEASE_STORE_FILE != null) {
storeFile file(System.env.MYAPP_RELEASE_STORE_FILE)
storePassword System.env.MYAPP_RELEASE_STORE_PASSWORD
keyAlias System.env.MYAPP_RELEASE_KEY_ALIAS
keyPassword System.env.MYAPP_RELEASE_KEY_PASSWORD
}
}
}
完成后,我可以加载一个bash脚本,其中包含
等详细信息# path to my keystore
export MYAPP_RELEASE_STORE_FILE=/path/to/key.file
# ...
这样签名配置与repo完全隔离。这可以防止您对自己的秘密进行意外提交。
答案 7 :(得分:1)
使用./gradlew bundleRelease比./gradlew assembleRelease
答案 8 :(得分:0)
确保已将 .keystore 文件放在app文件夹中,并进行如下所示的gradle更改:
signingConfigs {
release {
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}
答案 9 :(得分:0)
确保gradle.properties
中使用的别名与创建keystore
(使用keytool
)时使用的别名相同
答案 10 :(得分:0)
我放置在android / gradle.properties中的gradle.properties文件对我有用,看起来像最新的react .gradle / gradle.properties文件,如果我们将其放置在未从其选择的位置。
答案 11 :(得分:0)
在我的gradle.properties文件中,就像
MYAPP_RELEASE_STORE_FILE=<your-app>.keystore
MYAPP_RELEASE_KEY_ALIAS=<keystore-alias>
MYAPP_RELEASE_STORE_PASSWORD=<password>
MYAPP_RELEASE_KEY_PASSWORD=<password>
以及我的build.gradle文件
release {
if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {
storeFile file(MYAPP_UPLOAD_STORE_FILE)
storePassword MYAPP_UPLOAD_STORE_PASSWORD
keyAlias MYAPP_UPLOAD_KEY_ALIAS
keyPassword MYAPP_UPLOAD_KEY_PASSWORD
}
}
我在gradle.properties中使用了 RELEASE ,而不是 UPLOAD 。只是在gradle.properties中将 RELEASE 更改为 UPLOAD ,问题就解决了。