第26集使用uni-app开发APP并上架iOS全过程图文教程
|字数总计:3.5k|阅读时长:17分钟|阅读量:
引言
uni-app是DCloud公司推出的一个使用Vue.js开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web等多个平台。对于想要快速开发跨平台APP的开发者来说,uni-app是一个非常优秀的选择。
本文将详细介绍使用uni-app开发APP并上架iOS的全过程,从开发环境搭建到最终App Store上架,提供完整的图文教程和实战经验。
开发环境搭建
1. 安装HBuilderX
HBuilderX是uni-app官方推荐的开发工具,集成了uni-app的开发环境。
步骤1:下载HBuilderX
步骤2:安装HBuilderX
- 解压下载的压缩包
- 运行HBuilderX.exe(Windows)或HBuilderX.app(Mac)
2. 创建uni-app项目
步骤1:新建项目
- 打开HBuilderX
- 点击”文件” -> “新建” -> “项目”
- 选择”uni-app” -> “默认模板”
- 填写项目名称和路径
1 2 3 4 5 6 7 8 9 10 11 12
| my-uniapp-project/ ├── pages/ │ ├── index/ │ │ └── index.vue │ └── login/ │ └── login.vue ├── static/ ├── App.vue ├── main.js ├── manifest.json └── pages.json
|
步骤2:项目配置
在manifest.json
中配置应用基本信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| { "name": "我的APP", "appid": "__UNI__XXXXXXX", "description": "这是一个使用uni-app开发的跨平台应用", "versionName": "1.0.0", "versionCode": "100", "transformPx": false, "app-plus": { "usingComponents": true, "nvueStyleCompiler": "uni-app", "compilerVersion": 3, "splashscreen": { "alwaysShowBeforeRender": true, "waiting": true, "autoclose": true, "delay": 0 }, "modules": {}, "distribute": { "android": { "permissions": [ "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\" />", "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\" />", "<uses-permission android:name=\"android.permission.VIBRATE\" />", "<uses-permission android:name=\"android.permission.READ_LOGS\" />", "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />", "<uses-feature android:name=\"android.hardware.camera.autofocus\" />", "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />", "<uses-permission android:name=\"android.permission.CAMERA\" />", "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\" />", "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />", "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />", "<uses-permission android:name=\"android.permission.WAKE_LOCK\" />", "<uses-permission android:name=\"android.permission.FLASHLIGHT\" />", "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\" />" ] }, "ios": { "appstore": "true" }, "sdkConfigs": {} } }, "quickapp": {}, "mp-weixin": { "appid": "", "setting": { "urlCheck": false }, "usingComponents": true }, "mp-alipay": { "usingComponents": true }, "mp-baidu": { "usingComponents": true }, "mp-toutiao": { "usingComponents": true }, "uniStatistics": { "enable": false }, "vueVersion": "3" }
|
3. 开发环境配置
步骤1:安装Node.js
步骤2:安装uni-app CLI
1 2 3 4 5 6
| npm install -g @dcloudio/uvm uvm ls
npm install -g @dcloudio/cli
|
项目开发
1. 页面开发
首页开发示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| <!-- pages/index/index.vue --> <template> <view class="container"> <view class="header"> <text class="title">欢迎使用我的APP</text> </view> <view class="content"> <view class="card" v-for="(item, index) in list" :key="index"> <image :src="item.image" class="card-image"></image> <view class="card-content"> <text class="card-title">{{ item.title }}</text> <text class="card-desc">{{ item.description }}</text> </view> </view> </view> <view class="footer"> <button @click="goToLogin" class="login-btn">立即登录</button> </view> </view> </template>
<script> export default { data() { return { list: [ { title: '功能一', description: '这是功能一的描述', image: '/static/images/feature1.png' }, { title: '功能二', description: '这是功能二的描述', image: '/static/images/feature2.png' }, { title: '功能三', description: '这是功能三的描述', image: '/static/images/feature3.png' } ] } }, methods: { goToLogin() { uni.navigateTo({ url: '/pages/login/login' }) } } } </script>
<style> .container { padding: 20rpx; background-color: #f5f5f5; min-height: 100vh; }
.header { text-align: center; padding: 40rpx 0; }
.title { font-size: 36rpx; font-weight: bold; color: #333; }
.content { margin: 20rpx 0; }
.card { background-color: #fff; border-radius: 10rpx; padding: 20rpx; margin-bottom: 20rpx; display: flex; align-items: center; }
.card-image { width: 80rpx; height: 80rpx; margin-right: 20rpx; }
.card-content { flex: 1; }
.card-title { font-size: 32rpx; font-weight: bold; color: #333; display: block; margin-bottom: 10rpx; }
.card-desc { font-size: 28rpx; color: #666; display: block; }
.footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 20rpx; background-color: #fff; border-top: 1rpx solid #eee; }
.login-btn { width: 100%; height: 80rpx; background-color: #007aff; color: #fff; border-radius: 10rpx; font-size: 32rpx; border: none; } </style>
|
登录页面开发示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
| <!-- pages/login/login.vue --> <template> <view class="login-container"> <view class="login-header"> <image src="/static/images/logo.png" class="logo"></image> <text class="app-name">我的APP</text> </view> <view class="login-form"> <view class="input-group"> <input v-model="username" placeholder="请输入用户名" class="input" :class="{ 'error': usernameError }" /> <text v-if="usernameError" class="error-text">{{ usernameError }}</text> </view> <view class="input-group"> <input v-model="password" placeholder="请输入密码" password class="input" :class="{ 'error': passwordError }" /> <text v-if="passwordError" class="error-text">{{ passwordError }}</text> </view> <button @click="handleLogin" class="login-btn" :disabled="loading"> {{ loading ? '登录中...' : '登录' }} </button> </view> <view class="login-footer"> <text class="footer-text">还没有账号?</text> <text @click="goToRegister" class="register-link">立即注册</text> </view> </view> </template>
<script> export default { data() { return { username: '', password: '', usernameError: '', passwordError: '', loading: false } }, methods: { validateForm() { this.usernameError = '' this.passwordError = '' if (!this.username) { this.usernameError = '请输入用户名' return false } if (!this.password) { this.passwordError = '请输入密码' return false } if (this.password.length < 6) { this.passwordError = '密码长度不能少于6位' return false } return true }, async handleLogin() { if (!this.validateForm()) { return } this.loading = true try { // 模拟登录请求 const result = await this.loginRequest() if (result.success) { uni.showToast({ title: '登录成功', icon: 'success' }) // 保存用户信息 uni.setStorageSync('userInfo', result.data) // 跳转到首页 setTimeout(() => { uni.switchTab({ url: '/pages/index/index' }) }, 1500) } else { uni.showToast({ title: result.message || '登录失败', icon: 'none' }) } } catch (error) { uni.showToast({ title: '网络错误,请重试', icon: 'none' }) } finally { this.loading = false } }, loginRequest() { return new Promise((resolve) => { setTimeout(() => { if (this.username === 'admin' && this.password === '123456') { resolve({ success: true, data: { id: 1, username: this.username, nickname: '管理员' } }) } else { resolve({ success: false, message: '用户名或密码错误' }) } }, 1000) }) }, goToRegister() { uni.navigateTo({ url: '/pages/register/register' }) } } } </script>
<style> .login-container { padding: 40rpx; background-color: #f5f5f5; min-height: 100vh; }
.login-header { text-align: center; padding: 80rpx 0 60rpx; }
.logo { width: 120rpx; height: 120rpx; margin-bottom: 20rpx; }
.app-name { font-size: 40rpx; font-weight: bold; color: #333; }
.login-form { background-color: #fff; border-radius: 20rpx; padding: 40rpx; margin-bottom: 40rpx; }
.input-group { margin-bottom: 30rpx; }
.input { width: 100%; height: 80rpx; border: 2rpx solid #eee; border-radius: 10rpx; padding: 0 20rpx; font-size: 32rpx; box-sizing: border-box; }
.input.error { border-color: #ff4757; }
.error-text { color: #ff4757; font-size: 24rpx; margin-top: 10rpx; display: block; }
.login-btn { width: 100%; height: 80rpx; background-color: #007aff; color: #fff; border-radius: 10rpx; font-size: 32rpx; border: none; margin-top: 20rpx; }
.login-btn:disabled { background-color: #ccc; }
.login-footer { text-align: center; }
.footer-text { font-size: 28rpx; color: #666; }
.register-link { font-size: 28rpx; color: #007aff; margin-left: 10rpx; } </style>
|
2. 页面配置
pages.json配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| { "pages": [ { "path": "pages/index/index", "style": { "navigationBarTitleText": "首页", "enablePullDownRefresh": true } }, { "path": "pages/login/login", "style": { "navigationBarTitleText": "登录", "navigationStyle": "custom" } }, { "path": "pages/register/register", "style": { "navigationBarTitleText": "注册" } }, { "path": "pages/profile/profile", "style": { "navigationBarTitleText": "个人中心" } } ], "globalStyle": { "navigationBarTextStyle": "black", "navigationBarTitleText": "我的APP", "navigationBarBackgroundColor": "#F8F8F8", "backgroundColor": "#F8F8F8" }, "tabBar": { "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/index/index", "iconPath": "static/images/home.png", "selectedIconPath": "static/images/home-active.png", "text": "首页" }, { "pagePath": "pages/profile/profile", "iconPath": "static/images/profile.png", "selectedIconPath": "static/images/profile-active.png", "text": "我的" } ] }, "uniIdRouter": {} }
|
iOS证书配置
1. Apple Developer账号准备
步骤1:注册Apple Developer账号
步骤2:加入Apple Developer Program
- 点击”Enroll”加入开发者计划
- 选择个人开发者或企业开发者
- 支付年费(个人$99/年,企业$299/年)
2. 证书申请
步骤1:创建App ID
- 登录Apple Developer后台
- 进入”Certificates, Identifiers & Profiles”
- 点击”Identifiers” -> “+”
- 选择”App IDs” -> “Continue”
- 填写App ID信息:
- Description: 应用描述
- Bundle ID: 应用包名(如:com.yourcompany.yourapp)
步骤2:创建开发证书
- 点击”Certificates” -> “+”
- 选择”iOS App Development” -> “Continue”
- 上传CSR文件(Certificate Signing Request)
步骤3:创建发布证书
- 点击”Certificates” -> “+”
- 选择”iOS Distribution (App Store)” -> “Continue”
- 上传CSR文件
步骤4:创建Provisioning Profile
- 点击”Profiles” -> “+”
- 选择”iOS App Development” -> “Continue”
- 选择App ID -> “Continue”
- 选择证书 -> “Continue”
- 选择设备 -> “Continue”
- 填写Profile名称 -> “Generate”
3. HBuilderX证书配置
步骤1:配置iOS证书
- 打开HBuilderX
- 点击”发行” -> “原生App-云打包”
- 选择iOS平台
- 配置证书信息:
1 2 3 4 5 6 7 8
| { "ios": { "appstore": "true", "mobileprovision": "证书文件路径.mobileprovision", "p12": "证书文件路径.p12", "password": "证书密码" } }
|
步骤2:配置应用信息
- App名称:在App Store显示的名称
- Bundle ID:与Apple Developer中配置的一致
- 版本号:应用的版本号
- 构建号:每次打包递增
App Store上架流程
1. App Store Connect配置
步骤1:创建App
- 登录App Store Connect:https://appstoreconnect.apple.com/
- 点击”我的App” -> “+”
- 选择”新建App”
- 填写应用信息:
- 平台:iOS
- 名称:应用名称
- 主要语言:简体中文
- Bundle ID:选择已创建的App ID
- SKU:应用唯一标识符
步骤2:配置应用信息
- 填写应用描述
- 上传应用截图(不同尺寸)
- 设置应用分类
- 配置应用价格
2. 应用打包上传
步骤1:云打包
- 在HBuilderX中点击”发行” -> “原生App-云打包”
- 选择iOS平台
- 配置打包参数
- 点击”打包”
步骤2:下载安装包
- 打包完成后下载.ipa文件
- 使用Application Loader或Xcode上传到App Store Connect
步骤3:上传到App Store Connect
- 打开Xcode
- 选择”Window” -> “Organizer”
- 选择”Archives”
- 点击”Distribute App”
- 选择”App Store Connect”
- 上传应用
3. 应用审核
步骤1:提交审核
- 在App Store Connect中选择应用
- 点击”构建版本”
- 选择上传的版本
- 填写审核信息
- 提交审核
步骤2:审核要点
- 应用功能完整性
- 用户界面友好性
- 隐私政策合规性
- 内容符合App Store审核指南
常见问题解决
1. 证书问题
问题1:证书过期
问题2:Bundle ID不匹配
1 2 3 4 5 6 7 8 9 10
| { "app-plus": { "distribute": { "ios": { "bundleId": "com.yourcompany.yourapp" } } } }
|
2. 打包问题
问题1:打包失败
- 检查证书配置是否正确
- 确认网络连接正常
- 查看打包日志错误信息
问题2:应用崩溃
- 检查代码语法错误
- 确认API调用正确
- 测试真机运行
3. 审核问题
问题1:审核被拒
问题2:隐私政策缺失
性能优化建议
1. 代码优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
<image :src="item.image" lazy-load @load="onImageLoad" @error="onImageError" ></image>
<scroll-view scroll-y :refresher-enabled="true" :refresher-triggered="refreshing" @refresherrefresh="onRefresh" @scrolltolower="onLoadMore" > <view v-for="item in list" :key="item.id"> </view> </scroll-view>
|
2. 资源优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
{ "subPackages": [ { "root": "pages/sub", "pages": [ { "path": "page1/page1", "style": { "navigationBarTitleText": "页面1" } } ] } ] }
|
总结
使用uni-app开发APP并上架iOS是一个系统性的工程,需要掌握以下关键技能:
- 开发技能:Vue.js、uni-app框架、移动端开发
- 证书管理:Apple Developer账号、证书申请、配置管理
- 上架流程:App Store Connect、应用审核、版本管理
- 问题解决:常见问题排查、性能优化、合规性
通过本文的详细教程,相信您已经掌握了uni-app开发iOS应用的全过程。在实际开发中,建议:
- 充分测试应用功能
- 关注App Store审核指南
- 持续优化应用性能
- 及时处理用户反馈
参考资料
- uni-app官方文档
- Apple Developer文档
- App Store审核指南
- HBuilderX使用手册
- Vue.js官方文档