Practical Development of Smart Real Estate and Renovation Applications Based on HarmonyOS Next
1. Project Overview and Feature Planning
In today's digital real estate era, developing a comprehensive real estate and renovation application can provide users with one-stop services from property browsing to interior design. We will build such an application based on HarmonyOS Next and AppGallery Connect, featuring the following core functionalities:
- Property listing display and search
- 3D floor plan viewing
- Renovation design and sharing
- Contractor/designer matching
- Building materials marketplace
2. Development Environment and Project Initialization
2.1 Creating a HarmonyOS Project
Create a new project in DevEco Studio using the "Empty Ability" template with the following configuration:
// Basic configuration in entry/build-profile.json5
{
"app": {
"signingConfigs": [],
"compileSdkVersion": 9,
"compatibleSdkVersion": 9,
"products": [
{
"name": "default",
"signingConfig": "default",
"compileSdkVersion": "9",
"compatibleSdkVersion": "9",
"runtimeOS": "HarmonyOS"
}
]
}
}
2.2 Integrating AppGallery Connect Services
Add necessary dependencies in oh-package.json5
:
{
"dependencies": {
"@hw-agconnect/auth-ohos": "^1.8.0.300",
"@hw-agconnect/database-ohos": "^1.8.0.300",
"@hw-agconnect/storage-ohos": "^1.8.0.300",
"@hw-agconnect/cloudfunctions-ohos": "^1.8.0.300"
}
}
3. Property Listing Module Implementation
3.1 Property Data Model Design
// Property data model definition
class HouseInfo {
id: string = ''; // Property ID
title: string = ''; // Property title
price: number = 0; // Price (10K yuan)
area: number = 0; // Area (sqm)
roomType: string = ''; // Layout type
location: string = ''; // Location
coverUrl: string = ''; // Cover image URL
vrUrl?: string; // VR viewing link
tags: string[] = []; // Tags
createTime: string = ''; // Creation time
}
3.2 Property Listing Implementation
// Property listing page
@Entry
@Component
struct HouseListPage {
@State houseList: HouseInfo[] = []
@State loading: boolean = true
aboutToAppear() {
this.loadHouseData()
}
// Load property data
async loadHouseData() {
try {
const cloudDB = AGConnectCloudDB.getInstance()
const query = cloudDB.createQuery(HouseInfo)
const snapshot = await cloudDB.executeQuery(query)
this.houseList = snapshot.getSnapshotObjects()
} catch (error) {
console.error('Failed to load property data:', error)
} finally {
this.loading = false
}
}
build() {
Column() {
// Search bar
SearchBar({ placeholder: 'Enter community name or area' })
.width('90%')
.margin(10)
if (this.loading) {
LoadingProgress()
.height(100)
} else {
List({ space: 15 }) {
ForEach(this.houseList, (item: HouseInfo) => {
ListItem() {
HouseItemCard({ houseInfo: item })
}
})
}
.width('100%')
.layoutWeight(1)
}
}
}
}
// Property card component
@Component
struct HouseItemCard {
@Prop houseInfo: HouseInfo
build() {
Column() {
// Cover image
Image(this.houseInfo.coverUrl)
.width('100%')
.height(180)
.objectFit(ImageFit.Cover)
// Property information
Column({ space: 5 }) {
Text(this.houseInfo.title)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row() {
Text(`${this.houseInfo.price}万`)
.fontColor('#FF5722')
.fontSize(18)
Text(`· ${this.houseInfo.area}㎡`)
.margin({ left: 10 })
Text(`· ${this.houseInfo.roomType}`)
.margin({ left: 10 })
}
Text(this.houseInfo.location)
.fontSize(14)
.fontColor('#666')
// Tags
Wrap() {
ForEach(this.houseInfo.tags, (tag: string) => {
Text(tag)
.fontSize(12)
.padding(5)
.backgroundColor('#F5F5F5')
.borderRadius(4)
.margin({ right: 5, bottom: 5 })
})
}
.margin({ top: 5 })
}
.padding(10)
}
.width('90%')
.margin({ top: 5, bottom: 5 })
.borderRadius(8)
.backgroundColor(Color.White)
.shadow({ radius: 4, color: '#10000000', offsetX: 1, offsetY: 1 })
}
}
4. 3D Floor Plan Viewing Feature
4.1 Integrating 3D Model Viewer
// 3D floor plan viewing page
@Entry
@Component
struct House3DViewPage {
@State modelUrl: string = ''
@State loading: boolean = true
aboutToAppear() {
// Get model URL from route parameters
const params = router.getParams() as Record<string, string>
if (params && params['modelUrl']) {
this.modelUrl = params['modelUrl']
}
}
build() {
Stack() {
// 3D model container
Web({
src: this.modelUrl,
controller: new webview.WebviewController()
})
.onPageEnd(() => {
this.loading = false
})
if (this.loading) {
Column() {
LoadingProgress()
Text('Loading model...')
.margin({ top: 10 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
// Back button
Button()
.width(40)
.height(40)
.borderRadius(20)
.backgroundColor('#FFFFFF')
.margin({ top: 30, left: 15 })
.onClick(() => {
router.back()
})
}
.width('100%')
.height('100%')
}
}
5. Renovation Design Module Development
5.1 Renovation Plan Data Model
// Renovation plan data model
class DecorationPlan {
id: string = ''; // Plan ID
houseId: string = ''; // Associated property ID
title: string = ''; // Plan title
style: string = ''; // Design style
cost: number = 0; // Budget (10K yuan)
designer: string = ''; // Designer
designerAvatar: string = ''; // Designer avatar
images: string[] = []; // Renderings
createTime: string = ''; // Creation time
}
5.2 Renovation Plan List and Details
// Renovation plan list page
@Entry
@Component
struct DecorationListPage {
@State planList: DecorationPlan[] = []
@State selectedHouse: HouseInfo | null = null
aboutToAppear() {
this.loadDecorationPlans()
}
async loadDecorationPlans() {
try {
const cloudDB = AGConnectCloudDB.getInstance()
const query = cloudDB.createQuery(DecorationPlan)
const snapshot = await cloudDB.executeQuery(query)
this.planList = snapshot.getSnapshotObjects()
} catch (error) {
console.error('Failed to load renovation plans:', error)
}
}
build() {
Column() {
// Filter options
Row({ space: 10 }) {
Button('All')
.borderRadius(15)
.fontSize(14)
Button('Modern Minimalist')
.borderRadius(15)
.fontSize(14)
Button('Nordic Style')
.borderRadius(15)
.fontSize(14)
Button('New Chinese')
.borderRadius(15)
.fontSize(14)
}
.width('90%')
.margin({ top: 10, bottom: 10 })
// Plan list
Grid() {
ForEach(this.planList, (item: DecorationPlan) => {
GridItem() {
DecorationPlanCard({ plan: item })
}
})
}
.columnsTemplate('1fr 1fr')
.rowsTemplate('auto')
.columnsGap(10)
.rowsGap(10)
.width('90%')
.height('100%')
}
}
}
// Renovation plan card
@Component
struct DecorationPlanCard {
@Prop plan: DecorationPlan
build() {
Column() {
// Rendering cover
Stack() {
Image(this.plan.images[0])
.width('100%')
.height(120)
.objectFit(ImageFit.Cover)
// Designer information
Row() {
Image(this.plan.designerAvatar)
.width(24)
.height(24)
.borderRadius(12)
Text(this.plan.designer)
.fontSize(12)
.margin({ left: 5 })
}
.padding(5)
.backgroundColor('#80000000')
.borderRadius(12)
.position({ x: 5, y: 5 })
}
// Plan information
Column({ space: 3 }) {
Text(this.plan.title)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.maxLines(1)
Text(this.plan.style)
.fontSize(12)
.fontColor('#666')
Text(`Budget: ${this.plan.cost}万`)
.fontSize(12)
.fontColor('#FF5722')
}
.padding(8)
.width('100%')
}
.borderRadius(8)
.backgroundColor(Color.White)
.shadow({ radius: 2, color: '#10000000', offsetX: 1, offsetY: 1 })
}
}
6. Building Materials Marketplace Module Implementation
6.1 Building Material Product Data Model
// Building material product model
class BuildingMaterial {
id: string = ''; // Product ID
name: string = ''; // Product name
category: string = ''; // Category
brand: string = ''; // Brand
price: number = 0; // Price
unit: string = ''; // Unit
coverUrl: string = ''; // Cover image
specs: string[] = []; // Specifications
details: string = ''; // Description
}
6.2 Product List and Detail Page
// Building materials product list page
@Entry
@Component
struct MaterialListPage {
@State materialList: BuildingMaterial[] = []
@State activeCategory: string = 'All'
aboutToAppear() {
this.loadMaterials()
}
async loadMaterials() {
try {
const cloudDB = AGConnectCloudDB.getInstance()
let query = cloudDB.createQuery(BuildingMaterial)
if (this.activeCategory !== 'All') {
query = cloudDB.createQuery(
BuildingMaterial,
`category == '${this.activeCategory}'`
)
}
const snapshot = await cloudDB.executeQuery(query)
this.materialList = snapshot.getSnapshotObjects()
} catch (error) {
console.error('Failed to load building materials:', error)
}
}
build() {
Column() {
// Category filter
Scroll() {
Row({ space: 10 }) {
ForEach(['All', 'Flooring', 'Tiles', 'Bathroom', 'Lighting', 'Paint'], (item: string) => {
Button(item)
.borderRadius(15)
.fontSize(14)
.backgroundColor(this.activeCategory === item ? '#FF5722' : '#F5F5F5')
.fontColor(this.activeCategory === item ? Color.White : '#333')
.onClick(() => {
this.activeCategory = item
this.loadMaterials()
})
})
}
.padding(10)
}
.width('100%')
.height(50)
// Product list
List({ space: 15 }) {
ForEach(this.materialList, (item: BuildingMaterial) => {
ListItem() {
MaterialItemCard({ material: item })
}
})
}
.width('100%')
.layoutWeight(1)
}
}
}
// Product card component
@Component
struct MaterialItemCard {
@Prop material: BuildingMaterial
build() {
Row({ space: 10 }) {
Image(this.material.coverUrl)
.width(100)
.height(100)
.borderRadius(4)
.objectFit(ImageFit.Cover)
Column({ space: 5 }) {
Text(this.material.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.maxLines(1)
Text(this.material.brand)
.fontSize(14)
.fontColor('#666')
Row() {
Text(`¥${this.material.price}`)
.fontColor('#FF5722')
.fontSize(18)
Text(`/${this.material.unit}`)
.fontSize(14)
.fontColor('#999')
.margin({ left: 2 })
}
// Specification tags
Wrap() {
ForEach(this.material.specs, (spec: string) => {
Text(spec)
.fontSize(12)
.padding(3)
.backgroundColor('#F5F5F5')
.borderRadius(2)
.margin({ right: 5, bottom: 5 })
})
}
}
.layoutWeight(1)
}
.padding(10)
.width('90%')
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ top: 5, bottom: 5 })
}
}
7. Application Publishing and Operations
7.1 Application Packaging and Release
After completing development, follow these steps to publish the application:
- Configure application signing in DevEco Studio
- Execute Build > Build HAP(s)/APP(s) to generate the release package
- Log in to AppGallery Connect to submit the application for review
- Configure application metadata, screenshots, and promotional videos
7.2 Integrating Analytics
// Integrate analytics service at application entry
import { AGConnectAnalytics } from '@hw-agconnect/analytics-ohos';
export default class AppAnalytics {
static init() {
AGConnectAnalytics.getInstance().setAnalyticsEnabled(true)
// Set user attributes
AGConnectAnalytics.getInstance().setUserProfile('user_type', 'normal')
}
// Record page views
static trackPageView(pageName: string) {
AGConnectAnalytics.getInstance().onEvent('page_view', { page: pageName })
}
// Record user actions
static trackUserAction(action: string, params?: Record<string, string>) {
AGConnectAnalytics.getInstance().onEvent(action, params)
}
}
// Call in page lifecycle
AppAnalytics.init()
AppAnalytics.trackPageView('HomePage')
Through this comprehensive development process, we've implemented a fully functional real estate and renovation application. From property display to 3D viewing, from renovation design to building material selection, this solution covers the core scenarios of real estate renovation. The combination of HarmonyOS Next's distributed capabilities and AppGallery Connect's backend services provides developers with powerful technical support.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.