Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
Docs
提交
8f9059c7
D
Docs
项目概览
OpenHarmony
/
Docs
大约 2 年 前同步成功
通知
161
Star
293
Fork
28
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
Docs
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
8f9059c7
编写于
7月 14, 2023
作者:
W
wangqingkaihong
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
检视修改
Signed-off-by:
N
wangqingkaihong
<
wangqing@kaihong.com
>
上级
0196fee3
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
1020 addition
and
955 deletion
+1020
-955
zh-cn/third-party-cases/distributed-canvas.md
zh-cn/third-party-cases/distributed-canvas.md
+365
-350
zh-cn/third-party-cases/distributed-file.md
zh-cn/third-party-cases/distributed-file.md
+432
-391
zh-cn/third-party-cases/figures/camerapreview.gif
zh-cn/third-party-cases/figures/camerapreview.gif
+0
-0
zh-cn/third-party-cases/take-picture-and-preview.md
zh-cn/third-party-cases/take-picture-and-preview.md
+223
-214
未找到文件。
zh-cn/third-party-cases/distributed-canvas.md
浏览文件 @
8f9059c7
...
@@ -2,7 +2,9 @@
...
@@ -2,7 +2,9 @@
## 场景说明
## 场景说明
两台设备组网,实现修改文件时两个设备同时绘制的分布式画布场景有助于加快工作效率,减少工作中的冗余,本例将为大家介绍如何实现上述功能。
两台设备组网,当其中一个设备修改文件时,两个设备可以同步修改的结果。分布式场景可以在协同办公(如多人多设备编辑同一文件),设备文档更新(分布式设备更新文件内容,所有设备同步更新)中发挥重要作用,有助于加快工作效率,减少工作中的冗余。
本示例将为大家介绍如何实现上述功能。
## 效果呈现
## 效果呈现
...
@@ -40,358 +42,371 @@
...
@@ -40,358 +42,371 @@
## 开发步骤
## 开发步骤
1.
申请所需权限
1.
申请所需权限
在model.json5中添加以下配置:
在model.json5中添加以下配置:
```
json
```
json
"requestPermissions"
:
[
"requestPermissions"
:
[
{
{
"name"
:
"ohos.permission.DISTRIBUTED_DATASYNC"
//允许不同设备间的数据交换
"name"
:
"ohos.permission.DISTRIBUTED_DATASYNC"
//允许不同设备间的数据交换
},
},
{
{
"name"
:
"ohos.permission.ACCESS_SERVICE_DM"
//允许系统应用获取分布式设备的认证组网能力
"name"
:
"ohos.permission.ACCESS_SERVICE_DM"
//允许系统应用获取分布式设备的认证组网能力
}
}
]
]
```
```
2.
构建UI框架
2.
构建UI框架
indexCanvas页面:
indexCanvas页面:
```
typescript
TitleBar组件呈现标题栏。通过数据懒加载的方式遍历绘制的图形。被划出可视区域外的资源会被回收。
build
()
{
Column
()
{
绘制ellipse图形、rect图形的按钮使用Button组件呈现。
TitleBar
({
rightBtn
:
$r
(
'
app.media.trans
'
),
onRightBtnClicked
:
this
.
showDialog
})
//自/common/TitleBar.ets中引入标题栏相关。点击标题栏中的右侧按钮会调用showDialog()函数连接组网设备
返回按钮、删除按钮也通过Button组件呈现。
Row
()
{
Text
(
$r
(
'
app.string.state
'
))
```
typescript
.
fontSize
(
30
)
build
()
{
Image
(
this
.
isOnline
?
$r
(
'
app.media.green
'
)
:
$r
(
'
app.media.red
'
))
Column
()
{
.
size
({
width
:
30
,
height
:
30
})
TitleBar
({
rightBtn
:
$r
(
'
app.media.trans
'
),
onRightBtnClicked
:
this
.
showDialog
})
.
objectFit
(
ImageFit
.
Contain
)
//自/common/TitleBar.ets中引入标题栏相关。点击标题栏中的右侧按钮会调用showDialog()函数连接组网设备
}
Row
()
{
.
width
(
'
100%
'
)
Text
(
$r
(
'
app.string.state
'
))
.
padding
(
16
)
.
fontSize
(
30
)
//通过懒加载模式遍历绘制的图形,将每个图形绘制在画布上
Image
(
this
.
isOnline
?
$r
(
'
app.media.green
'
)
:
$r
(
'
app.media.red
'
))
LazyForEach
(
this
.
canvasDataSource
,
(
item
:
CanvasPath
,
index
)
=>
{
.
size
({
width
:
30
,
height
:
30
})
Canvas
(
this
.
context
)
.
objectFit
(
ImageFit
.
Contain
)
.
width
(
'
100%
'
)
}
.
height
(
200
)
.
width
(
'
100%
'
)
.
backgroundColor
(
'
#00ffff
'
)
.
padding
(
16
)
.
onReady
(()
=>
{
//通过懒加载模式遍历绘制的图形,将每个图形绘制在画布上
if
(
item
.
path
===
'
rect
'
)
{
LazyForEach
(
this
.
canvasDataSource
,
(
item
:
CanvasPath
,
index
)
=>
{
this
.
context
.
save
();
Canvas
(
this
.
context
)
this
.
path2Df
.
rect
(
80
,
80
,
100
,
100
);
.
width
(
'
100%
'
)
this
.
context
.
stroke
(
this
.
path2Df
);
.
height
(
200
)
this
.
context
.
restore
();
.
backgroundColor
(
'
#00ffff
'
)
}
.
onReady
(()
=>
{
if
(
item
.
path
===
'
ellipse
'
)
{
if
(
item
.
path
===
'
rect
'
)
{
this
.
context
.
restore
();
this
.
context
.
save
();
this
.
path2De
.
ellipse
(
100
,
100
,
50
,
100
,
Math
.
PI
*
0.25
,
Math
.
PI
*
0.5
,
Math
.
PI
);
this
.
path2Df
.
rect
(
80
,
80
,
100
,
100
);
this
.
context
.
stroke
(
this
.
path2De
);
this
.
context
.
stroke
(
this
.
path2Df
);
this
.
context
.
save
();
this
.
context
.
restore
();
}
}
})
if
(
item
.
path
===
'
ellipse
'
)
{
},
item
=>
JSON
.
stringify
(
item
))
this
.
context
.
restore
();
this
.
path2De
.
ellipse
(
100
,
100
,
50
,
100
,
Math
.
PI
*
0.25
,
Math
.
PI
*
0.5
,
Math
.
PI
);
Row
()
{
this
.
context
.
stroke
(
this
.
path2De
);
Button
(
'
ellipse
'
)
//绘制ellipse图形的按钮
this
.
context
.
save
();
.
width
(
130
)
}
.
height
(
45
)
})
.
key
(
'
ellipse
'
)
},
item
=>
JSON
.
stringify
(
item
))
.
onClick
(()
=>
{
if
(
this
.
globalObject
.
isContainString
(
'
ellipse
'
)
===
-
1
)
{
Row
()
{
this
.
globalObject
.
add
(
'
ellipse
'
);
//将绘制信息保存在持久全局数据中
Button
(
'
ellipse
'
)
//绘制ellipse图形的按钮
}
.
width
(
130
)
this
.
onPageShow
();
.
height
(
45
)
})
.
key
(
'
ellipse
'
)
Button
(
'
rect
'
)
//绘制rect图形的按钮
.
onClick
(()
=>
{
.
width
(
130
)
if
(
this
.
globalObject
.
isContainString
(
'
ellipse
'
)
===
-
1
)
{
.
height
(
45
)
this
.
globalObject
.
add
(
'
ellipse
'
);
//将绘制信息保存在持久全局数据中
.
key
(
'
rect
'
)
}
.
onClick
(()
=>
{
this
.
onPageShow
();
if
(
this
.
globalObject
.
isContainString
(
'
rect
'
)
===
-
1
)
{
})
this
.
globalObject
.
add
(
'
rect
'
);
Button
(
'
rect
'
)
//绘制rect图形的按钮
}
.
width
(
130
)
this
.
onPageShow
();
.
height
(
45
)
})
.
key
(
'
rect
'
)
}.
margin
({
top
:
10
})
.
onClick
(()
=>
{
.
width
(
'
100%
'
)
if
(
this
.
globalObject
.
isContainString
(
'
rect
'
)
===
-
1
)
{
.
justifyContent
(
FlexAlign
.
SpaceAround
)
this
.
globalObject
.
add
(
'
rect
'
);
}
Row
()
{
this
.
onPageShow
();
Button
(
'
back
'
)
})
.
width
(
130
)
}.
margin
({
top
:
10
})
.
height
(
45
)
.
width
(
'
100%
'
)
.
key
(
'
back
'
)
.
justifyContent
(
FlexAlign
.
SpaceAround
)
.
backgroundColor
(
Color
.
Orange
)
.
onClick
(()
=>
{
Row
()
{
router
.
back
()
Button
(
'
back
'
)
})
.
width
(
130
)
Button
(
'
delete
'
)
//删除图形
.
height
(
45
)
.
width
(
130
)
.
key
(
'
back
'
)
.
height
(
45
)
.
backgroundColor
(
Color
.
Orange
)
.
key
(
'
delete
'
)
.
onClick
(()
=>
{
.
onClick
(()
=>
{
router
.
back
()
this
.
globalObject
.
clear
();
})
this
.
canvasDataSource
[
'
pathArray
'
]
=
[];
Button
(
'
delete
'
)
//删除图形
this
.
canvasDataSource
.
notifyDataReload
();
.
width
(
130
)
this
.
context
.
clearRect
(
0
,
0
,
950
,
950
)
.
height
(
45
)
})
.
key
(
'
delete
'
)
}.
margin
({
top
:
10
})
.
onClick
(()
=>
{
.
width
(
'
100%
'
)
this
.
globalObject
.
clear
();
.
justifyContent
(
FlexAlign
.
SpaceAround
)
this
.
canvasDataSource
[
'
pathArray
'
]
=
[];
}
this
.
canvasDataSource
.
notifyDataReload
();
.
width
(
'
100%
'
)
this
.
context
.
clearRect
(
0
,
0
,
950
,
950
)
.
height
(
'
100%
'
)
})
.
justifyContent
(
FlexAlign
.
Center
)
}.
margin
({
top
:
10
})
.
alignItems
(
HorizontalAlign
.
Center
)
.
width
(
'
100%
'
)
}
.
justifyContent
(
FlexAlign
.
SpaceAround
)
}
}
```
.
width
(
'
100%
'
)
.
height
(
'
100%
'
)
2.
数据model
.
justifyContent
(
FlexAlign
.
Center
)
.
alignItems
(
HorizontalAlign
.
Center
)
```
}
//BasicDataSource.ets
}
class BasicDataSource implements IDataSource {
```
private listeners: DataChangeListener[] = []
3.
数据model
public totalCount(): number {
return 0
通过registerDataChangeListener进行对数据变动的监听,数据发生变化时,调用notifyDataReload方法通知数据已经准备就绪。
}
```
typescript
public getData(index: number): any {
//BasicDataSource.ets
return undefined
class
BasicDataSource
implements
IDataSource
{
}
private
listeners
:
DataChangeListener
[]
=
[]
//注册数据变动的监听
public
totalCount
():
number
{
registerDataChangeListener(listener: DataChangeListener): void {
return
0
if (this.listeners.indexOf(listener) < 0) {
}
console.info('add listener')
this.listeners.push(listener)
public
getData
(
index
:
number
):
any
{
}
return
undefined
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
//注册数据变动的监听
const pos = this.listeners.indexOf(listener);
registerDataChangeListener
(
listener
:
DataChangeListener
):
void
{
if (pos >= 0) {
if
(
this
.
listeners
.
indexOf
(
listener
)
<
0
)
{
console.info('remove listener')
console
.
info
(
'
add listener
'
)
this.listeners.splice(pos, 1)
this
.
listeners
.
push
(
listener
)
}
}
}
}
//数据reloaded,分布式数据数值变化需要调用这个接口重载下
unregisterDataChangeListener
(
listener
:
DataChangeListener
):
void
{
notifyDataReload(): void {
const
pos
=
this
.
listeners
.
indexOf
(
listener
);
this.listeners.forEach(listener => {
if
(
pos
>=
0
)
{
listener.onDataReloaded()
console
.
info
(
'
remove listener
'
)
})
this
.
listeners
.
splice
(
pos
,
1
)
}
}
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
//数据reloaded,分布式数据数值变化需要调用这个接口重载下
listener.onDataAdd(index)
notifyDataReload
():
void
{
})
this
.
listeners
.
forEach
(
listener
=>
{
}
listener
.
onDataReloaded
()
})
....
}
export class CanvasDataSource extends BasicDataSource {
notifyDataAdd
(
index
:
number
):
void
{
//监听的数据类型
this
.
listeners
.
forEach
(
listener
=>
{
private pathArray: Canvas[] = []
listener
.
onDataAdd
(
index
)
})
//重载接口
}
public totalCount(): number {
return this.pathArray.length
....
}
export
class
CanvasDataSource
extends
BasicDataSource
{
public getData(index: number): any {
//监听的数据类型
return this.pathArray[index]
private
pathArray
:
Canvas
[]
=
[]
}
//重载接口
public addData(index: number, data: Canvas): void {
public
totalCount
():
number
{
this.pathArray.splice(index, 0, data)
return
this
.
pathArray
.
length
this.notifyDataAdd(index)
}
}
public
getData
(
index
:
number
):
any
{
public pushData(data: Canvas): void {
return
this
.
pathArray
[
index
]
this.pathArray.push(data)
}
this.notifyDataAdd(this.pathArray.length - 1)
}
public
addData
(
index
:
number
,
data
:
Canvas
):
void
{
}
this
.
pathArray
.
splice
(
index
,
0
,
data
)
```
this
.
notifyDataAdd
(
index
)
}
3.
将两台设备组网
public
pushData
(
data
:
Canvas
):
void
{
```
typescript
this
.
pathArray
.
push
(
data
)
showDialog
=
()
=>
{
this
.
notifyDataAdd
(
this
.
pathArray
.
length
-
1
)
//RemoteDeviceModel引入自model/RemoteDeviceModel.ts
}
RemoteDeviceModel
.
registerDeviceListCallback
(()
=>
{
}
//得到附近可信的设备列表
```
Logger
.
info
(
TAG
,
'
registerDeviceListCallback, callback entered
'
)
this
.
devices
=
[]
4.
将两台设备组网
this
.
devices
=
RemoteDeviceModel
.
discoverDevices
.
length
>
0
?
RemoteDeviceModel
.
discoverDevices
:
RemoteDeviceModel
.
devices
if
(
this
.
dialogController
)
{
使用自RemoteDeviceModel.ts中引入的类RemoteDeviceModel以扫描获得附近可以连接的设备。
this
.
dialogController
.
close
()
this
.
dialogController
=
undefined
```
typescript
}
showDialog
=
()
=>
{
this
.
dialogController
=
new
CustomDialogController
({
//RemoteDeviceModel引入自model/RemoteDeviceModel.ts
builder
:
DeviceDialog
({
RemoteDeviceModel
.
registerDeviceListCallback
(()
=>
{
devices
:
this
.
devices
,
//得到附近可信的设备列表
onSelectedIndexChange
:
this
.
onSelectedDevice
Logger
.
info
(
TAG
,
'
registerDeviceListCallback, callback entered
'
)
}),
this
.
devices
=
[]
autoCancel
:
true
this
.
devices
=
RemoteDeviceModel
.
discoverDevices
.
length
>
0
?
RemoteDeviceModel
.
discoverDevices
:
RemoteDeviceModel
.
devices
})
if
(
this
.
dialogController
)
{
this
.
dialogController
.
open
()
this
.
dialogController
.
close
()
})
this
.
dialogController
=
undefined
}
}
....................................
this
.
dialogController
=
new
CustomDialogController
({
//model/RemoteDeviceModel.ts
builder
:
DeviceDialog
({
import
deviceManager
from
'
@ohos.distributedHardware.deviceManager
'
devices
:
this
.
devices
,
registerDeviceListCallback
(
stateChangeCallback
:
()
=>
void
)
{
onSelectedIndexChange
:
this
.
onSelectedDevice
if
(
typeof
(
this
.
deviceManager
)
!==
'
undefined
'
)
{
}),
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
autoCancel
:
true
return
})
}
this
.
dialogController
.
open
()
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager begin
'
)
})
try
{
}
deviceManager
.
createDeviceManager
(
BUNDLE
,
(
error
,
value
)
=>
{
....................................
if
(
error
)
{
//model/RemoteDeviceModel.ts
Logger
.
error
(
TAG
,
'
createDeviceManager failed.
'
)
import
deviceManager
from
'
@ohos.distributedHardware.deviceManager
'
return
registerDeviceListCallback
(
stateChangeCallback
:
()
=>
void
)
{
}
if
(
typeof
(
this
.
deviceManager
)
!==
'
undefined
'
)
{
this
.
deviceManager
=
value
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
return
Logger
.
info
(
TAG
,
`createDeviceManager callback returned,value=
${
value
}
`
)
}
})
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager begin
'
)
}
catch
(
error
)
{
try
{
Logger
.
error
(
TAG
,
`createDeviceManager throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
deviceManager
.
createDeviceManager
(
BUNDLE
,
(
error
,
value
)
=>
{
}
if
(
error
)
{
Logger
.
error
(
TAG
,
'
createDeviceManager failed.
'
)
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager end
'
)
return
}
}
registerDeviceListCallbackImplement
(
stateChangeCallback
:
()
=>
void
)
{
this
.
deviceManager
=
value
Logger
.
info
(
TAG
,
'
registerDeviceListCallback
'
)
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
this
.
stateChangeCallback
=
stateChangeCallback
Logger
.
info
(
TAG
,
`createDeviceManager callback returned,value=
${
value
}
`
)
if
(
this
.
deviceManager
===
undefined
)
{
})
Logger
.
error
(
TAG
,
'
deviceManager has not initialized
'
)
}
catch
(
error
)
{
this
.
stateChangeCallback
()
Logger
.
error
(
TAG
,
`createDeviceManager throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
return
}
}
Logger
.
info
(
TAG
,
'
getTrustedDeviceListSync begin
'
)
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager end
'
)
try
{
}
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
//同步获取所有可信设备列表
registerDeviceListCallbackImplement
(
stateChangeCallback
:
()
=>
void
)
{
Logger
.
info
(
TAG
,
`getTrustedDeviceListSync end, devices=
${
JSON
.
stringify
(
list
)}
`
)
Logger
.
info
(
TAG
,
'
registerDeviceListCallback
'
)
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
this
.
stateChangeCallback
=
stateChangeCallback
this
.
devices
=
list
if
(
this
.
deviceManager
===
undefined
)
{
}
Logger
.
error
(
TAG
,
'
deviceManager has not initialized
'
)
}
catch
(
error
)
{
this
.
stateChangeCallback
()
Logger
.
error
(
TAG
,
`getLocalDeviceInfoSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
return
}
}
this
.
stateChangeCallback
()
Logger
.
info
(
TAG
,
'
getTrustedDeviceListSync begin
'
)
Logger
.
info
(
TAG
,
'
callback finished
'
)
try
{
try
{
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
//同步获取所有可信设备列表
this
.
deviceManager
.
on
(
'
deviceStateChange
'
,
(
data
)
=>
{
Logger
.
info
(
TAG
,
`getTrustedDeviceListSync end, devices=
${
JSON
.
stringify
(
list
)}
`
)
if
(
data
===
null
)
{
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
return
this
.
devices
=
list
}
}
Logger
.
info
(
TAG
,
`deviceStateChange data =
${
JSON
.
stringify
(
data
)}
`
)
}
catch
(
error
)
{
switch
(
data
.
action
)
{
Logger
.
error
(
TAG
,
`getLocalDeviceInfoSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
case
deviceManager
.
DeviceStateChangeAction
.
READY
:
//即设备处于可用状态,表示设备间信息已在分布式数据中同步完成, 可以运行分布式业务
}
this
.
discoverDevices
=
[]
this
.
stateChangeCallback
()
this
.
devices
.
push
(
data
.
device
)
Logger
.
info
(
TAG
,
'
callback finished
'
)
this
.
stateChangeCallback
()
try
{
try
{
this
.
deviceManager
.
on
(
'
deviceStateChange
'
,
(
data
)
=>
{
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
if
(
data
===
null
)
{
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
return
this
.
devices
=
list
}
}
Logger
.
info
(
TAG
,
`deviceStateChange data =
${
JSON
.
stringify
(
data
)}
`
)
}
catch
(
error
)
{
switch
(
data
.
action
)
{
Logger
.
error
(
TAG
,
`getTrustedDeviceListSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
case
deviceManager
.
DeviceStateChangeAction
.
READY
:
//即设备处于可用状态,表示设备间信息已在分布式数据中同步完成, 可以运行分布式业务
}
this
.
discoverDevices
=
[]
this
.
stateChangeCallback
()
this
.
devices
.
push
(
data
.
device
)
break
this
.
stateChangeCallback
()
default
:
try
{
break
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
}
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
})
this
.
devices
=
list
this
.
deviceManager
.
on
(
'
deviceFound
'
,
(
data
)
=>
{
}
if
(
data
===
null
)
{
}
catch
(
error
)
{
return
Logger
.
error
(
TAG
,
`getTrustedDeviceListSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
}
}
Logger
.
info
(
TAG
,
`deviceFound data=
${
JSON
.
stringify
(
data
)}
`
)
this
.
stateChangeCallback
()
this
.
onDeviceFound
(
data
)
break
})
default
:
this
.
deviceManager
.
on
(
'
discoverFail
'
,
(
data
)
=>
{
break
Logger
.
info
(
TAG
,
`discoverFail data=
${
JSON
.
stringify
(
data
)}
`
)
}
})
})
this
.
deviceManager
.
on
(
'
serviceDie
'
,
()
=>
{
this
.
deviceManager
.
on
(
'
deviceFound
'
,
(
data
)
=>
{
Logger
.
info
(
TAG
,
'
serviceDie
'
)
if
(
data
===
null
)
{
})
return
}
catch
(
error
)
{
}
Logger
.
error
(
TAG
,
`on throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
Logger
.
info
(
TAG
,
`deviceFound data=
${
JSON
.
stringify
(
data
)}
`
)
}
this
.
onDeviceFound
(
data
)
this
.
startDeviceDiscovery
()
})
}
this
.
deviceManager
.
on
(
'
discoverFail
'
,
(
data
)
=>
{
startDeviceDiscovery
()
{
Logger
.
info
(
TAG
,
`discoverFail data=
${
JSON
.
stringify
(
data
)}
`
)
SUBSCRIBE_ID
=
Math
.
floor
(
65536
*
Math
.
random
())
})
var
info
=
{
this
.
deviceManager
.
on
(
'
serviceDie
'
,
()
=>
{
subscribeId
:
SUBSCRIBE_ID
,
Logger
.
info
(
TAG
,
'
serviceDie
'
)
mode
:
0xAA
,
})
medium
:
2
,
}
catch
(
error
)
{
freq
:
2
,
//高频率
Logger
.
error
(
TAG
,
`on throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
isSameAccount
:
false
,
}
isWakeRemote
:
true
,
this
.
startDeviceDiscovery
()
capability
:
0
}
}
startDeviceDiscovery
()
{
Logger
.
info
(
TAG
,
`startDeviceDiscovery
${
SUBSCRIBE_ID
}
`
)
SUBSCRIBE_ID
=
Math
.
floor
(
65536
*
Math
.
random
())
try
{
var
info
=
{
this
.
deviceManager
.
startDeviceDiscovery
(
info
)
//开始发现周边设备
subscribeId
:
SUBSCRIBE_ID
,
}
catch
(
error
)
{
mode
:
0xAA
,
Logger
.
error
(
TAG
,
`startDeviceDiscovery throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
medium
:
2
,
}
freq
:
2
,
//高频率
isSameAccount
:
false
,
}
isWakeRemote
:
true
,
```
capability
:
0
}
4.
实现同步编辑
Logger
.
info
(
TAG
,
`startDeviceDiscovery
${
SUBSCRIBE_ID
}
`
)
try
{
```
typescript
this
.
deviceManager
.
startDeviceDiscovery
(
info
)
//开始发现周边设备
onPageShow
()
{
}
catch
(
error
)
{
//每当完成编辑或者新建文件,就会回到主页,此时就会执行onPageShow()
Logger
.
error
(
TAG
,
`startDeviceDiscovery throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
}
this
.
noteDataSource
.
notifyDataReload
()
Logger
.
info
(
TAG
,
`this.sessionId =
${
this
.
sessionId
}
`
)
}
Logger
.
info
(
TAG
,
`globalSessionId =
${
this
.
globalSessionId
}
`
)
```
if
(
this
.
sessionId
!==
this
.
globalSessionId
)
{
this
.
sessionId
=
this
.
globalSessionId
5.
实现同步编辑
this
.
share
()
}
通过AppStorage设置持久性数据,然后实现IDataSource接口,通过注册数据监听接口监听数据的变化。
}
share
()
{
```
typescript
//多个设备间的对象如果设置为同一个sessionId的笔记数据自动同步
onPageShow
()
{
Logger
.
info
(
TAG
,
`sessionId =
${
this
.
sessionId
}
`
)
//每当完成编辑或者新建文件,就会回到主页,此时就会执行onPageShow()
this
.
globalObject
.
setChangeCallback
(()
=>
{
//noteDataSource获取globalObject保存的分布式的持久性数据,并进行Reload操作传递。
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
this
.
noteDataSource
.
notifyDataReload
()
this
.
noteDataSource
.
notifyDataReload
()
})
Logger
.
info
(
TAG
,
`this.sessionId =
${
this
.
sessionId
}
`
)
this
.
globalObject
.
setStatusCallback
((
session
,
networkId
,
status
)
=>
{
Logger
.
info
(
TAG
,
`globalSessionId =
${
this
.
globalSessionId
}
`
)
Logger
.
info
(
TAG
,
`StatusCallback,
${
status
}
`
)
if
(
this
.
sessionId
!==
this
.
globalSessionId
)
{
if
(
status
===
'
online
'
)
{
this
.
sessionId
=
this
.
globalSessionId
this
.
isOnline
=
true
this
.
share
()
}
else
{
}
this
.
isOnline
=
false
}
}
share
()
{
})
//多个设备间的对象如果设置为同一个sessionId,数据自动同步
this
.
globalObject
.
distributedObject
.
setSessionId
(
this
.
sessionId
)
Logger
.
info
(
TAG
,
`sessionId =
${
this
.
sessionId
}
`
)
AppStorage
.
SetOrCreate
(
'
objectModel
'
,
this
.
globalObject
)
this
.
globalObject
.
setChangeCallback
(()
=>
{
}
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
```
this
.
noteDataSource
.
notifyDataReload
()
})
this
.
globalObject
.
setStatusCallback
((
session
,
networkId
,
status
)
=>
{
Logger
.
info
(
TAG
,
`StatusCallback,
${
status
}
`
)
if
(
status
===
'
online
'
)
{
this
.
isOnline
=
true
}
else
{
this
.
isOnline
=
false
}
})
this
.
globalObject
.
distributedObject
.
setSessionId
(
this
.
sessionId
)
AppStorage
.
SetOrCreate
(
'
objectModel
'
,
this
.
globalObject
)
}
```
## 全部代码
## 全部代码
本例完整代码sample示例链接:
[
分布式
文件
](
https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedNote
)
本例完整代码sample示例链接:
[
分布式
对象
](
https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedNote
)
## 参考
## 参考
...
...
zh-cn/third-party-cases/distributed-file.md
浏览文件 @
8f9059c7
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
## 场景说明
## 场景说明
两台设备组网
,实现修改文件时两个设备同时修改的分布式文件
场景有助于加快工作效率,减少工作中的冗余,本例将为大家介绍如何实现上述功能。
两台设备组网
的分布式场景是工作中常常需要的。常见的如代码的同步编辑、文档的同步修改等。这样的分布式
场景有助于加快工作效率,减少工作中的冗余,本例将为大家介绍如何实现上述功能。
## 效果呈现
## 效果呈现
...
@@ -40,402 +40,443 @@
...
@@ -40,402 +40,443 @@
## 开发步骤
## 开发步骤
1.
申请所需权限
1.
申请所需权限
在model.json5中添加以下配置:
在model.json5中添加以下配置:
```
json
```
json
"requestPermissions"
:
[
"requestPermissions"
:
[
{
{
"name"
:
"ohos.permission.DISTRIBUTED_DATASYNC"
//允许不同设备间的数据交换
"name"
:
"ohos.permission.DISTRIBUTED_DATASYNC"
//允许不同设备间的数据交换
},
},
{
{
"name"
:
"ohos.permission.ACCESS_SERVICE_DM"
//允许系统应用获取分布式设备的认证组网能力
"name"
:
"ohos.permission.ACCESS_SERVICE_DM"
//允许系统应用获取分布式设备的认证组网能力
}
}
]
]
```
```
2.
构建UI框架
2.
构建UI框架
indexNote页面:
index页面:
```
typescript
TitleBar组件呈现标题栏。使用List组件呈现文件列表,ListItem由一个呈现文件类型标志的Image组件,一个呈现文件标题的Text组件,一个呈现文件内容的Text组件组成。
build
()
{
```
typescript
Column
()
{
build
()
{
TitleBar
({
rightBtn
:
$r
(
'
app.media.trans
'
),
onRightBtnClicked
:
this
.
showDialog
})
Column
()
{
//自/common/TitleBar.ets中引入标题栏相关。点击标题栏中的右侧按钮会调用showDialog()函数连接组网设备
TitleBar
({
rightBtn
:
$r
(
'
app.media.trans
'
),
onRightBtnClicked
:
this
.
showDialog
})
Row
()
{
//自/common/TitleBar.ets中引入标题栏相关。点击标题栏中的右侧按钮会调用showDialog()函数连接组网设备
Text
(
$r
(
'
app.string.state
'
))
Row
()
{
.
fontSize
(
30
)
Text
(
$r
(
'
app.string.state
'
))
Image
(
this
.
isOnline
?
$r
(
'
app.media.green
'
)
:
$r
(
'
app.media.red
'
))
//两台设备组网成功后状态显示为绿色、否则为红色
.
fontSize
(
30
)
.
size
({
width
:
30
,
height
:
30
})
Image
(
this
.
isOnline
?
$r
(
'
app.media.green
'
)
:
$r
(
'
app.media.red
'
))
//两台设备组网成功后状态显示为绿色、否则为红色
.
objectFit
(
ImageFit
.
Contain
)
.
size
({
width
:
30
,
height
:
30
})
}
.
objectFit
(
ImageFit
.
Contain
)
.
width
(
'
100%
'
)
}
.
padding
(
16
)
.
width
(
'
100%
'
)
//通过数据懒加载的方式从数据源中每次迭代一个文件进行展示,可用列表被放置在滚动容器中,被划出可视区域外的资源会被回收
.
padding
(
16
)
List
({
space
:
10
})
{
//通过数据懒加载的方式从数据源中每次迭代一个文件进行展示,可用列表被放置在滚动容器中,被划出可视区域外的资源会被回收
LazyForEach
(
this
.
noteDataSource
,
(
item
:
Note
,
index
)
=>
{
List
({
space
:
10
})
{
ListItem
()
{
LazyForEach
(
this
.
noteDataSource
,
(
item
:
Note
,
index
)
=>
{
NoteItem
({
note
:
item
,
index
:
index
})
//NoteItem引入自common/NoteItem.ets,负责主页文件信息的呈现
ListItem
()
{
.
id
(
`
${
item
.
title
}
`
)
NoteItem
({
note
:
item
,
index
:
index
})
//NoteItem引入自common/NoteItem.ets,负责主页文件信息的呈现
}
.
id
(
`
${
item
.
title
}
`
)
},
item
=>
JSON
.
stringify
(
item
))
}
}
},
item
=>
JSON
.
stringify
(
item
))
.
width
(
'
95%
'
)
}
.
margin
(
10
)
.
width
(
'
95%
'
)
.
layoutWeight
(
1
)
.
margin
(
10
)
.
layoutWeight
(
1
)
Row
()
{
Column
()
{
Row
()
{
Image
(
$r
(
'
app.media.clear
'
))
//清除按钮
Column
()
{
.
size
({
width
:
40
,
height
:
40
})
Image
(
$r
(
'
app.media.clear
'
))
//清除按钮
Text
(
$r
(
'
app.string.clear
'
))
.
size
({
width
:
40
,
height
:
40
})
.
fontColor
(
Color
.
Red
)
Text
(
$r
(
'
app.string.clear
'
))
.
fontSize
(
20
)
.
fontColor
(
Color
.
Red
)
}.
layoutWeight
(
1
)
.
fontSize
(
20
)
.
id
(
'
clearNote
'
)
}.
layoutWeight
(
1
)
.
onClick
(()
=>
{
.
id
(
'
clearNote
'
)
//点击清除按钮清除所有文件
.
onClick
(()
=>
{
Logger
.
info
(
TAG
,
'
clear notes
'
)
//点击清除按钮清除所有文件
this
.
noteDataSource
[
'
dataArray
'
]
=
[]
Logger
.
info
(
TAG
,
'
clear notes
'
)
this
.
noteDataSource
.
notifyDataReload
()
this
.
noteDataSource
[
'
dataArray
'
]
=
[]
this
.
globalObject
.
clear
()
this
.
noteDataSource
.
notifyDataReload
()
AppStorage
.
SetOrCreate
(
'
sessionId
'
,
this
.
sessionId
)
this
.
globalObject
.
clear
()
})
AppStorage
.
SetOrCreate
(
'
sessionId
'
,
this
.
sessionId
)
})
Column
()
{
Image
(
$r
(
'
app.media.add
'
))
//添加按钮
Column
()
{
.
size
({
width
:
40
,
height
:
40
})
Image
(
$r
(
'
app.media.add
'
))
//添加按钮
Text
(
$r
(
'
app.string.add
'
))
.
size
({
width
:
40
,
height
:
40
})
.
fontColor
(
Color
.
Black
)
Text
(
$r
(
'
app.string.add
'
))
.
fontSize
(
20
)
.
fontColor
(
Color
.
Black
)
}.
layoutWeight
(
1
)
.
fontSize
(
20
)
.
id
(
'
addNote
'
)
}.
layoutWeight
(
1
)
.
onClick
(()
=>
{
.
id
(
'
addNote
'
)
//点击添加按钮跳转到编辑页面
.
onClick
(()
=>
{
router
.
push
({
//点击添加按钮跳转到编辑页面
url
:
'
pages/Edit
'
,
router
.
push
({
params
:
{
url
:
'
pages/Edit
'
,
note
:
new
Note
(
''
,
''
,
-
1
),
params
:
{
isAdd
:
true
note
:
new
Note
(
''
,
''
,
-
1
),
}
isAdd
:
true
})
}
})
})
}
})
.
width
(
'
100%
'
)
}
.
padding
(
10
)
.
width
(
'
100%
'
)
.
backgroundColor
(
'
#F0F0F0
'
)
.
padding
(
10
)
}
.
backgroundColor
(
'
#F0F0F0
'
)
.
width
(
'
100%
'
)
}
.
height
(
'
100%
'
)
.
width
(
'
100%
'
)
.
backgroundColor
(
'
#F5F5F5
'
)
.
height
(
'
100%
'
)
}
.
backgroundColor
(
'
#F5F5F5
'
)
}
}
....................................
}
//common/NoteItem.ets
...
import
router
from
'
@ohos.router
'
//common/NoteItem.ets
import
{
MARKS
}
from
'
../model/Const
'
import
router
from
'
@ohos.router
'
import
Note
from
'
../model/Note
'
import
{
MARKS
}
from
'
../model/Const
'
import
Note
from
'
../model/Note
'
@
Component
export
default
struct
NoteItem
{
@
Component
@
State
note
:
Note
|
undefined
=
undefined
export
default
struct
NoteItem
{
private
index
:
number
=
0
@
State
note
:
Note
|
undefined
=
undefined
private
index
:
number
=
0
build
()
{
Row
()
{
build
()
{
Image
(
this
.
note
.
mark
>=
0
?
MARKS
[
this
.
note
.
mark
]
:
$r
(
'
app.media.note
'
))
//文件标志图片
Row
()
{
.
size
({
width
:
30
,
height
:
30
})
Image
(
this
.
note
.
mark
>=
0
?
MARKS
[
this
.
note
.
mark
]
:
$r
(
'
app.media.note
'
))
//文件标志图片
.
objectFit
(
ImageFit
.
Contain
)
.
size
({
width
:
30
,
height
:
30
})
Column
()
{
.
objectFit
(
ImageFit
.
Contain
)
Text
(
this
.
note
.
title
)
//文件标题
Column
()
{
.
fontColor
(
Color
.
Black
)
Text
(
this
.
note
.
title
)
//文件标题
.
fontSize
(
30
)
.
fontColor
(
Color
.
Black
)
.
maxLines
(
1
)
.
fontSize
(
30
)
.
textOverflow
({
overflow
:
TextOverflow
.
Ellipsis
})
.
maxLines
(
1
)
Text
(
this
.
note
.
content
)
//文件内容
.
textOverflow
({
overflow
:
TextOverflow
.
Ellipsis
})
.
fontColor
(
Color
.
Gray
)
Text
(
this
.
note
.
content
)
//文件内容
.
margin
({
top
:
10
})
.
fontColor
(
Color
.
Gray
)
.
fontSize
(
25
)
.
margin
({
top
:
10
})
.
maxLines
(
1
)
//在列表中最多展示一行
.
fontSize
(
25
)
.
textOverflow
({
overflow
:
TextOverflow
.
Ellipsis
})
.
maxLines
(
1
)
//在列表中最多展示一行
}
.
textOverflow
({
overflow
:
TextOverflow
.
Ellipsis
})
.
alignItems
(
HorizontalAlign
.
Start
)
}
.
margin
({
left
:
20
})
.
alignItems
(
HorizontalAlign
.
Start
)
}
.
margin
({
left
:
20
})
.
padding
(
16
)
}
.
width
(
'
100%
'
)
.
padding
(
16
)
.
borderRadius
(
16
)
.
width
(
'
100%
'
)
.
backgroundColor
(
Color
.
White
)
.
borderRadius
(
16
)
.
onClick
(()
=>
{
.
backgroundColor
(
Color
.
White
)
//点击文件进入此文件编辑页面
.
onClick
(()
=>
{
router
.
push
({
//点击文件进入此文件编辑页面
url
:
'
pages/Edit
'
,
router
.
push
({
params
:
{
url
:
'
pages/Edit
'
,
index
:
this
.
index
,
params
:
{
note
:
this
.
note
,
index
:
this
.
index
,
isAdd
:
false
note
:
this
.
note
,
}
isAdd
:
false
})
}
})
})
}
})
}
}
```
}
```
Edit页面:
Edit页面:
```
typescript
build
()
{
使用TextInput组件呈现文件标题输入框,使用TextArea组件呈现文件内容的输入区域,使用Button组件呈现保存按钮并绑定点击事件以新建或更新文件内容。
Column
()
{
TitleBar
({
title
:
this
.
note
.
title
===
''
?
$r
(
'
app.string.add_note
'
)
:
this
.
note
.
title
})
```
typescript
Column
()
{
build
()
{
Row
()
{
Column
()
{
Image
(
this
.
note
.
mark
>=
0
?
MARKS
[
this
.
note
.
mark
]
:
$r
(
'
app.media.mark
'
))
TitleBar
({
title
:
this
.
note
.
title
===
''
?
$r
(
'
app.string.add_note
'
)
:
this
.
note
.
title
})
.
width
(
30
)
Column
()
{
.
aspectRatio
(
1
)
Row
()
{
.
margin
({
left
:
16
,
top
:
16
})
Image
(
this
.
note
.
mark
>=
0
?
MARKS
[
this
.
note
.
mark
]
:
$r
(
'
app.media.mark
'
))
.
objectFit
(
ImageFit
.
Contain
)
.
width
(
30
)
.
alignSelf
(
ItemAlign
.
Start
)
.
aspectRatio
(
1
)
Select
([{
value
:
'
'
,
icon
:
MARKS
[
0
]
},
.
margin
({
left
:
16
,
top
:
16
})
{
value
:
'
'
,
icon
:
MARKS
[
1
]
},
.
objectFit
(
ImageFit
.
Contain
)
{
value
:
'
'
,
icon
:
MARKS
[
2
]
},
.
alignSelf
(
ItemAlign
.
Start
)
{
value
:
'
'
,
icon
:
MARKS
[
3
]
},
Select
([{
value
:
'
'
,
icon
:
MARKS
[
0
]
},
{
value
:
'
'
,
icon
:
MARKS
[
4
]
}])
{
value
:
'
'
,
icon
:
MARKS
[
1
]
},
.
selected
(
this
.
note
.
mark
)
{
value
:
'
'
,
icon
:
MARKS
[
2
]
},
.
margin
({
top
:
5
})
{
value
:
'
'
,
icon
:
MARKS
[
3
]
},
.
onSelect
((
index
:
number
)
=>
{
{
value
:
'
'
,
icon
:
MARKS
[
4
]
}])
this
.
note
.
mark
=
index
.
selected
(
this
.
note
.
mark
)
})
.
margin
({
top
:
5
})
}
.
onSelect
((
index
:
number
)
=>
{
.
width
(
'
100%
'
)
this
.
note
.
mark
=
index
})
TextInput
({
placeholder
:
'
input the title
'
,
text
:
this
.
note
.
title
})
//文件标题输入框
}
.
id
(
'
titleInput
'
)
.
width
(
'
100%
'
)
.
placeholderColor
(
Color
.
Gray
)
.
fontSize
(
30
)
TextInput
({
placeholder
:
'
input the title
'
,
text
:
this
.
note
.
title
})
//文件标题输入框
.
margin
({
left
:
15
,
right
:
15
,
top
:
15
})
.
id
(
'
titleInput
'
)
.
height
(
60
)
.
placeholderColor
(
Color
.
Gray
)
.
backgroundColor
(
Color
.
White
)
.
fontSize
(
30
)
.
onChange
((
value
:
string
)
=>
{
.
margin
({
left
:
15
,
right
:
15
,
top
:
15
})
this
.
note
.
title
=
value
.
height
(
60
)
})
.
backgroundColor
(
Color
.
White
)
TextArea
({
placeholder
:
'
input the content
'
,
text
:
this
.
note
.
content
})
//文件内容输入区域
.
onChange
((
value
:
string
)
=>
{
.
id
(
'
contentInput
'
)
this
.
note
.
title
=
value
.
placeholderColor
(
Color
.
Gray
)
})
.
backgroundColor
(
Color
.
White
)
TextArea
({
placeholder
:
'
input the content
'
,
text
:
this
.
note
.
content
})
//文件内容输入区域
.
fontSize
(
30
)
.
id
(
'
contentInput
'
)
.
height
(
'
35%
'
)
.
placeholderColor
(
Color
.
Gray
)
.
margin
({
left
:
16
,
right
:
16
,
top
:
16
})
.
backgroundColor
(
Color
.
White
)
.
textAlign
(
TextAlign
.
Start
)
.
fontSize
(
30
)
.
onChange
((
value
:
string
)
=>
{
.
height
(
'
35%
'
)
this
.
note
.
content
=
value
.
margin
({
left
:
16
,
right
:
16
,
top
:
16
})
})
.
textAlign
(
TextAlign
.
Start
)
.
onChange
((
value
:
string
)
=>
{
Button
()
{
this
.
note
.
content
=
value
//保存按钮
})
Text
(
$r
(
'
app.string.save
'
))
.
fontColor
(
Color
.
White
)
Button
()
{
.
fontSize
(
17
)
//保存按钮
}
Text
(
$r
(
'
app.string.save
'
))
.
id
(
'
saveNote
'
)
.
fontColor
(
Color
.
White
)
.
backgroundColor
(
'
#0D9FFB
'
)
.
fontSize
(
17
)
.
height
(
50
)
}
.
width
(
200
)
.
id
(
'
saveNote
'
)
.
margin
({
top
:
20
})
.
backgroundColor
(
'
#0D9FFB
'
)
.
onClick
(()
=>
{
.
height
(
50
)
//点击按钮时调用model/DistributedObjectModel.ts定义的类globalObject中的方法
.
width
(
200
)
if
(
!
this
.
isAdd
)
{
.
margin
({
top
:
20
})
let
index
=
router
.
getParams
()[
'
index
'
]
.
onClick
(()
=>
{
this
.
globalObject
.
update
(
index
,
this
.
note
.
title
,
this
.
note
.
content
,
this
.
note
.
mark
)
//编辑时更新内容
//点击按钮时调用model/DistributedObjectModel.ts定义的类globalObject中的方法
}
else
{
if
(
!
this
.
isAdd
)
{
this
.
globalObject
.
add
(
this
.
note
.
title
,
this
.
note
.
content
,
this
.
note
.
mark
)
//新建时添加内容
let
index
=
router
.
getParams
()[
'
index
'
]
}
this
.
globalObject
.
update
(
index
,
this
.
note
.
title
,
this
.
note
.
content
,
this
.
note
.
mark
)
//编辑时更新内容
router
.
back
()
//返回主页
}
else
{
})
this
.
globalObject
.
add
(
this
.
note
.
title
,
this
.
note
.
content
,
this
.
note
.
mark
)
//新建时添加内容
}
}
}
router
.
back
()
//返回主页
.
width
(
'
100%
'
)
})
.
height
(
'
100%
'
)
}
.
backgroundColor
(
'
#F5F5F5
'
)
}
}
.
width
(
'
100%
'
)
}
.
height
(
'
100%
'
)
```
.
backgroundColor
(
'
#F5F5F5
'
)
}
3.
将两台设备组网
}
```
```
typescript
showDialog
=
()
=>
{
3.
将两台设备组网
//RemoteDeviceModel引入自model/RemoteDeviceModel.ts
RemoteDeviceModel
.
registerDeviceListCallback
(()
=>
{
使用自RemoteDeviceModel.ts中引入的类RemoteDeviceModel以扫描获得附近可以连接的设备。
//得到附近可信的设备列表
Logger
.
info
(
TAG
,
'
registerDeviceListCallback, callback entered
'
)
```
typescript
this
.
devices
=
[]
showDialog
=
()
=>
{
this
.
devices
=
RemoteDeviceModel
.
discoverDevices
.
length
>
0
?
RemoteDeviceModel
.
discoverDevices
:
RemoteDeviceModel
.
devices
//RemoteDeviceModel引入自model/RemoteDeviceModel.ts
if
(
this
.
dialogController
)
{
RemoteDeviceModel
.
registerDeviceListCallback
(()
=>
{
this
.
dialogController
.
close
()
//得到附近可信的设备列表
this
.
dialogController
=
undefined
Logger
.
info
(
TAG
,
'
registerDeviceListCallback, callback entered
'
)
}
this
.
devices
=
[]
this
.
dialogController
=
new
CustomDialogController
({
this
.
devices
=
RemoteDeviceModel
.
discoverDevices
.
length
>
0
?
RemoteDeviceModel
.
discoverDevices
:
RemoteDeviceModel
.
devices
builder
:
DeviceDialog
({
if
(
this
.
dialogController
)
{
devices
:
this
.
devices
,
this
.
dialogController
.
close
()
onSelectedIndexChange
:
this
.
onSelectedDevice
this
.
dialogController
=
undefined
}),
}
autoCancel
:
true
this
.
dialogController
=
new
CustomDialogController
({
})
builder
:
DeviceDialog
({
this
.
dialogController
.
open
()
devices
:
this
.
devices
,
})
onSelectedIndexChange
:
this
.
onSelectedDevice
}
}),
....................................
autoCancel
:
true
//model/RemoteDeviceModel.ts
})
import
deviceManager
from
'
@ohos.distributedHardware.deviceManager
'
this
.
dialogController
.
open
()
registerDeviceListCallback
(
stateChangeCallback
:
()
=>
void
)
{
})
if
(
typeof
(
this
.
deviceManager
)
!==
'
undefined
'
)
{
}
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
...
return
//model/RemoteDeviceModel.ts
}
import
deviceManager
from
'
@ohos.distributedHardware.deviceManager
'
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager begin
'
)
registerDeviceListCallback
(
stateChangeCallback
:
()
=>
void
)
{
try
{
if
(
typeof
(
this
.
deviceManager
)
!==
'
undefined
'
)
{
deviceManager
.
createDeviceManager
(
BUNDLE
,
(
error
,
value
)
=>
{
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
if
(
error
)
{
return
Logger
.
error
(
TAG
,
'
createDeviceManager failed.
'
)
}
return
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager begin
'
)
}
try
{
this
.
deviceManager
=
value
deviceManager
.
createDeviceManager
(
BUNDLE
,
(
error
,
value
)
=>
{
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
if
(
error
)
{
Logger
.
info
(
TAG
,
`createDeviceManager callback returned,value=
${
value
}
`
)
Logger
.
error
(
TAG
,
'
createDeviceManager failed.
'
)
})
return
}
catch
(
error
)
{
}
Logger
.
error
(
TAG
,
`createDeviceManager throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
this
.
deviceManager
=
value
}
this
.
registerDeviceListCallbackImplement
(
stateChangeCallback
)
Logger
.
info
(
TAG
,
`createDeviceManager callback returned,value=
${
value
}
`
)
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager end
'
)
})
}
}
catch
(
error
)
{
registerDeviceListCallbackImplement
(
stateChangeCallback
:
()
=>
void
)
{
Logger
.
error
(
TAG
,
`createDeviceManager throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
Logger
.
info
(
TAG
,
'
registerDeviceListCallback
'
)
}
this
.
stateChangeCallback
=
stateChangeCallback
if
(
this
.
deviceManager
===
undefined
)
{
Logger
.
info
(
TAG
,
'
deviceManager.createDeviceManager end
'
)
Logger
.
error
(
TAG
,
'
deviceManager has not initialized
'
)
}
this
.
stateChangeCallback
()
registerDeviceListCallbackImplement
(
stateChangeCallback
:
()
=>
void
)
{
return
Logger
.
info
(
TAG
,
'
registerDeviceListCallback
'
)
}
this
.
stateChangeCallback
=
stateChangeCallback
Logger
.
info
(
TAG
,
'
getTrustedDeviceListSync begin
'
)
if
(
this
.
deviceManager
===
undefined
)
{
try
{
Logger
.
error
(
TAG
,
'
deviceManager has not initialized
'
)
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
//同步获取所有可信设备列表
this
.
stateChangeCallback
()
Logger
.
info
(
TAG
,
`getTrustedDeviceListSync end, devices=
${
JSON
.
stringify
(
list
)}
`
)
return
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
}
this
.
devices
=
list
Logger
.
info
(
TAG
,
'
getTrustedDeviceListSync begin
'
)
}
try
{
}
catch
(
error
)
{
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
//同步获取所有可信设备列表
Logger
.
error
(
TAG
,
`getLocalDeviceInfoSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
Logger
.
info
(
TAG
,
`getTrustedDeviceListSync end, devices=
${
JSON
.
stringify
(
list
)}
`
)
}
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
this
.
stateChangeCallback
()
this
.
devices
=
list
Logger
.
info
(
TAG
,
'
callback finished
'
)
}
try
{
}
catch
(
error
)
{
this
.
deviceManager
.
on
(
'
deviceStateChange
'
,
(
data
)
=>
{
Logger
.
error
(
TAG
,
`getLocalDeviceInfoSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
if
(
data
===
null
)
{
}
return
this
.
stateChangeCallback
()
}
Logger
.
info
(
TAG
,
'
callback finished
'
)
Logger
.
info
(
TAG
,
`deviceStateChange data =
${
JSON
.
stringify
(
data
)}
`
)
try
{
switch
(
data
.
action
)
{
this
.
deviceManager
.
on
(
'
deviceStateChange
'
,
(
data
)
=>
{
case
deviceManager
.
DeviceStateChangeAction
.
READY
:
//即设备处于可用状态,表示设备间信息已在分布式数据中同步完成, 可以运行分布式业务
if
(
data
===
null
)
{
this
.
discoverDevices
=
[]
return
this
.
devices
.
push
(
data
.
device
)
}
this
.
stateChangeCallback
()
Logger
.
info
(
TAG
,
`deviceStateChange data =
${
JSON
.
stringify
(
data
)}
`
)
try
{
switch
(
data
.
action
)
{
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
case
deviceManager
.
DeviceStateChangeAction
.
READY
:
//即设备处于可用状态,表示设备间信息已在分布式数据中同步完成, 可以运行分布式业务
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
this
.
discoverDevices
=
[]
this
.
devices
=
list
this
.
devices
.
push
(
data
.
device
)
}
this
.
stateChangeCallback
()
}
catch
(
error
)
{
try
{
Logger
.
error
(
TAG
,
`getTrustedDeviceListSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
let
list
=
this
.
deviceManager
.
getTrustedDeviceListSync
()
}
if
(
typeof
(
list
)
!==
'
undefined
'
&&
typeof
(
list
.
length
)
!==
'
undefined
'
)
{
this
.
stateChangeCallback
()
this
.
devices
=
list
break
}
default
:
}
catch
(
error
)
{
break
Logger
.
error
(
TAG
,
`getTrustedDeviceListSync throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
}
}
})
this
.
stateChangeCallback
()
this
.
deviceManager
.
on
(
'
deviceFound
'
,
(
data
)
=>
{
break
if
(
data
===
null
)
{
default
:
return
break
}
}
Logger
.
info
(
TAG
,
`deviceFound data=
${
JSON
.
stringify
(
data
)}
`
)
})
this
.
onDeviceFound
(
data
)
this
.
deviceManager
.
on
(
'
deviceFound
'
,
(
data
)
=>
{
})
if
(
data
===
null
)
{
this
.
deviceManager
.
on
(
'
discoverFail
'
,
(
data
)
=>
{
return
Logger
.
info
(
TAG
,
`discoverFail data=
${
JSON
.
stringify
(
data
)}
`
)
}
})
Logger
.
info
(
TAG
,
`deviceFound data=
${
JSON
.
stringify
(
data
)}
`
)
this
.
deviceManager
.
on
(
'
serviceDie
'
,
()
=>
{
this
.
onDeviceFound
(
data
)
Logger
.
info
(
TAG
,
'
serviceDie
'
)
})
})
this
.
deviceManager
.
on
(
'
discoverFail
'
,
(
data
)
=>
{
}
catch
(
error
)
{
Logger
.
info
(
TAG
,
`discoverFail data=
${
JSON
.
stringify
(
data
)}
`
)
Logger
.
error
(
TAG
,
`on throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
})
}
this
.
deviceManager
.
on
(
'
serviceDie
'
,
()
=>
{
this
.
startDeviceDiscovery
()
Logger
.
info
(
TAG
,
'
serviceDie
'
)
}
})
startDeviceDiscovery
()
{
}
catch
(
error
)
{
SUBSCRIBE_ID
=
Math
.
floor
(
65536
*
Math
.
random
())
Logger
.
error
(
TAG
,
`on throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
var
info
=
{
}
subscribeId
:
SUBSCRIBE_ID
,
this
.
startDeviceDiscovery
()
mode
:
0xAA
,
}
medium
:
2
,
startDeviceDiscovery
()
{
freq
:
2
,
//高频率
SUBSCRIBE_ID
=
Math
.
floor
(
65536
*
Math
.
random
())
isSameAccount
:
false
,
var
info
=
{
isWakeRemote
:
true
,
subscribeId
:
SUBSCRIBE_ID
,
capability
:
0
mode
:
0xAA
,
}
medium
:
2
,
Logger
.
info
(
TAG
,
`startDeviceDiscovery
${
SUBSCRIBE_ID
}
`
)
freq
:
2
,
//高频率
try
{
isSameAccount
:
false
,
this
.
deviceManager
.
startDeviceDiscovery
(
info
)
//开始发现周边设备
isWakeRemote
:
true
,
}
catch
(
error
)
{
capability
:
0
Logger
.
error
(
TAG
,
`startDeviceDiscovery throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
}
}
Logger
.
info
(
TAG
,
`startDeviceDiscovery
${
SUBSCRIBE_ID
}
`
)
try
{
}
this
.
deviceManager
.
startDeviceDiscovery
(
info
)
//开始发现周边设备
```
}
catch
(
error
)
{
Logger
.
error
(
TAG
,
`startDeviceDiscovery throw error, code=
${
error
.
code
}
message=
${
error
.
message
}
`
)
4.
实现同步编辑
}
```
typescript
}
onPageShow
()
{
```
//每当完成编辑或者新建文件,就会回到主页,此时就会执行onPageShow()
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
4.
实现同步编辑
this
.
noteDataSource
.
notifyDataReload
()
Logger
.
info
(
TAG
,
`this.sessionId =
${
this
.
sessionId
}
`
)
通过AppStorage设置持久性数据,然后实现IDataSource接口,通过注册数据监听接口监听数据的变化。
Logger
.
info
(
TAG
,
`globalSessionId =
${
this
.
globalSessionId
}
`
)
if
(
this
.
sessionId
!==
this
.
globalSessionId
)
{
```
typescript
this
.
sessionId
=
this
.
globalSessionId
class
BasicDataSource
implements
IDataSource
{
this
.
share
()
private
listeners
:
DataChangeListener
[]
=
[]
}
}
public
totalCount
():
number
{
share
()
{
return
0
//多个设备间的对象如果设置为同一个sessionId的笔记数据自动同步
}
Logger
.
info
(
TAG
,
`sessionId =
${
this
.
sessionId
}
`
)
this
.
globalObject
.
setChangeCallback
(()
=>
{
public
getData
(
index
:
number
):
any
{
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
return
undefined
this
.
noteDataSource
.
notifyDataReload
()
}
})
this
.
globalObject
.
setStatusCallback
((
session
,
networkId
,
status
)
=>
{
registerDataChangeListener
(
listener
:
DataChangeListener
):
void
{
Logger
.
info
(
TAG
,
`StatusCallback,
${
status
}
`
)
if
(
this
.
listeners
.
indexOf
(
listener
)
<
0
)
{
if
(
status
===
'
online
'
)
{
console
.
info
(
'
add listener
'
)
this
.
isOnline
=
true
this
.
listeners
.
push
(
listener
)
}
else
{
}
this
.
isOnline
=
false
}
}
})
unregisterDataChangeListener
(
listener
:
DataChangeListener
):
void
{
this
.
globalObject
.
distributedObject
.
setSessionId
(
this
.
sessionId
)
const
pos
=
this
.
listeners
.
indexOf
(
listener
);
AppStorage
.
SetOrCreate
(
'
objectModel
'
,
this
.
globalObject
)
if
(
pos
>=
0
)
{
}
console
.
info
(
'
remove listener
'
)
```
this
.
listeners
.
splice
(
pos
,
1
)
}
}
//数据准备好了
notifyDataReload
():
void
{
this
.
listeners
.
forEach
(
listener
=>
{
listener
.
onDataReloaded
()
})
}
...
}
onPageShow
()
{
//每当完成编辑或者新建文件,就会回到主页,此时就会执行onPageShow()
//noteDataSource获取globalObject保存的分布式的持久性数据,并进行Reload操作传递。
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
this
.
noteDataSource
.
notifyDataReload
()
Logger
.
info
(
TAG
,
`this.sessionId =
${
this
.
sessionId
}
`
)
Logger
.
info
(
TAG
,
`globalSessionId =
${
this
.
globalSessionId
}
`
)
if
(
this
.
sessionId
!==
this
.
globalSessionId
)
{
this
.
sessionId
=
this
.
globalSessionId
this
.
share
()
}
}
share
()
{
//多个设备间的对象如果设置为同一个sessionId的笔记数据自动同步
Logger
.
info
(
TAG
,
`sessionId =
${
this
.
sessionId
}
`
)
this
.
globalObject
.
setChangeCallback
(()
=>
{
this
.
noteDataSource
[
'
dataArray
'
]
=
this
.
globalObject
.
distributedObject
.
documents
this
.
noteDataSource
.
notifyDataReload
()
})
this
.
globalObject
.
setStatusCallback
((
session
,
networkId
,
status
)
=>
{
Logger
.
info
(
TAG
,
`StatusCallback,
${
status
}
`
)
if
(
status
===
'
online
'
)
{
this
.
isOnline
=
true
}
else
{
this
.
isOnline
=
false
}
})
this
.
globalObject
.
distributedObject
.
setSessionId
(
this
.
sessionId
)
AppStorage
.
SetOrCreate
(
'
objectModel
'
,
this
.
globalObject
)
}
```
## 全部代码
## 全部代码
本例完整代码sample示例链接:
[
分布式
文件
](
https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedNote
)
本例完整代码sample示例链接:
[
分布式
对象
](
https://gitee.com/openharmony/applications_app_samples/tree/master/code/SuperFeature/DistributedAppDev/DistributedNote
)
## 参考
## 参考
[
权限列表
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync
)
-
[
权限列表
](
../application-dev/security/permission-list.md#ohospermissiondistributed_datasync
)
-
[
分布式数据对象
](
../application-dev/reference/apis/js-apis-data-distributedobject.md
)
[
分布式数据对象
](
../application-dev/reference/apis/js-apis-data-distributedobject.md
)
zh-cn/third-party-cases/figures/camerapreview.gif
0 → 100644
浏览文件 @
8f9059c7
9.9 MB
zh-cn/third-party-cases/take-picture-and-preview.md
浏览文件 @
8f9059c7
...
@@ -8,10 +8,16 @@
...
@@ -8,10 +8,16 @@
本例效果如下:
本例效果如下:

| 拍照 | 预览 |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
<img
src=
"figures/camera.png"
alt=
"contactlist"
style=
"zoom: 45%;"
/>
|
<img
src=
"figures/camerapreview.gif"
alt=
"contactlist"
style=
"zoom: 50%;"
/>
|
## 运行环境
## 运行环境
本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发。
-
IDE:DevEco Studio 4.0.0.201 Beta1
-
IDE:DevEco Studio 4.0.0.201 Beta1
-
SDK:Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
-
SDK:Ohos_sdk_public 4.0.7.5 (API Version 10 Beta1)
...
@@ -19,222 +25,224 @@
...
@@ -19,222 +25,224 @@
本例使用@ohos.multimedia.camera接口实现相机示例的主要功能:拍照、预览;
本例使用@ohos.multimedia.camera接口实现相机示例的主要功能:拍照、预览;
使用@ohos.multimedia.image接口实现图片接收;
-
拍照:XComponent组件负责绘制摄像头画面呈现的窗口,其onload事件调用cameraModel.ts的initCamera方法初始化相机功能输出画面信息。拍照动作使用Image组件实现,其onclick事件调用cameraModel.ts的takepicture方法开始拍照。
使用@ohos.multimedia.mediaLibrary接口实现对媒体文件的存储。
-
XComponent组件负责绘制摄像头画面呈现的窗口,其onload事件调用cameraModel.ts的initCamera方法初始化相机功能输出预览信息。
-
预览:返回相机界面点击底部左侧预览图可进入相册应用,可以在其中查看照片和录制的视频。
-
拍照按钮:使用Image组件实现,其onclick事件调用cameraModel.ts的takepicture方法开始拍照。
-
照片存储:MediaModel.ts中的createAndGetUri方法通过引用自@ohos.multimedia.mediaLibrary的mediaLibraryTest类创建媒体资源,saveImage方法将拍摄的照片写入到Mediamodel传回的资源中去。
## 开发步骤
## 开发步骤
1.
申请所需权限
1.
申请所需权限
在model.json5中添加以下配置:
在model.json5中添加以下配置:
```
json
```
json
"requestPermissions"
:
[
"requestPermissions"
:
[
{
{
"name"
:
"ohos.permission.CAMERA"
//允许应用使用相机拍摄照片和录制视频
"name"
:
"ohos.permission.CAMERA"
//允许应用使用相机拍摄照片和录制视频
},
},
{
{
"name"
:
"ohos.permission.MICROPHONE"
//允许应用使用麦克风
"name"
:
"ohos.permission.MICROPHONE"
//允许应用使用麦克风
},
},
{
{
"name"
:
"ohos.permission.MEDIA_LOCATION"
//允许应用访问用户媒体文件中的地理位置信息
"name"
:
"ohos.permission.MEDIA_LOCATION"
//允许应用访问用户媒体文件中的地理位置信息
},
},
{
{
"name"
:
"ohos.permission.WRITE_MEDIA"
//允许应用读写用户外部存储中的媒体文件信息
"name"
:
"ohos.permission.WRITE_MEDIA"
//允许应用读写用户外部存储中的媒体文件信息
},
},
{
{
"name"
:
"ohos.permission.READ_MEDIA"
//允许应用读取用户外部存储中的媒体文件信息
"name"
:
"ohos.permission.READ_MEDIA"
//允许应用读取用户外部存储中的媒体文件信息
}
}
]
]
```
```
2.
创建绘制组件XComponent
2.
创建绘制组件XComponent以输出摄像头获取的画面,其绑定的onload方法中设定了画幅的大小。
```
typescript
```
typescript
build
()
{
build
()
{
Column
()
{
Column
()
{
Title
()
Title
()
.
visibility
(
this
.
isTitleShow
?
Visibility
.
Visible
:
Visibility
.
None
)
.
visibility
(
this
.
isTitleShow
?
Visibility
.
Visible
:
Visibility
.
None
)
Stack
({
alignContent
:
Alignment
.
Bottom
})
{
Stack
({
alignContent
:
Alignment
.
Bottom
})
{
Stack
({
alignContent
:
Alignment
.
TopStart
})
{
Stack
({
alignContent
:
Alignment
.
TopStart
})
{
XComponent
({
XComponent
({
id
:
'
componentId
'
,
id
:
'
componentId
'
,
type
:
'
surface
'
,
type
:
'
surface
'
,
controller
:
this
.
mXComponentController
//将控制器绑定至XComponent组件
controller
:
this
.
mXComponentController
//将控制器绑定至XComponent组件
})
})
.
onLoad
(()
=>
{
.
onLoad
(()
=>
{
this
.
mXComponentController
.
setXComponentSurfaceSize
({
surfaceWidth
:
640
,
surfaceHeight
:
480
});
//设置surface大小
this
.
mXComponentController
.
setXComponentSurfaceSize
({
surfaceWidth
:
640
,
surfaceHeight
:
480
});
//设置surface大小
this
.
surfaceId
=
this
.
mXComponentController
.
getXComponentSurfaceId
();
this
.
surfaceId
=
this
.
mXComponentController
.
getXComponentSurfaceId
();
this
.
currentModel
=
CameraMode
.
modePhoto
;
this
.
currentModel
=
CameraMode
.
modePhoto
;
this
.
cameraModel
.
initCamera
(
this
.
surfaceId
);
//调用model/cameraModel.ts初始化相机功能
this
.
cameraModel
.
initCamera
(
this
.
surfaceId
);
//调用model/cameraModel.ts初始化相机功能
})
})
.
width
(
'
100%
'
)
.
width
(
'
100%
'
)
.
height
(
'
100%
'
)
.
height
(
'
100%
'
)
.
margin
({
bottom
:
152
})
.
margin
({
bottom
:
152
})
Column
()
{
Column
()
{
}
}
.
width
(
'
97%
'
)
.
width
(
'
97%
'
)
.
height
(
'
100%
'
)
.
height
(
'
100%
'
)
```
```
3.
初始化相机功能
3.
初始化相机功能
```
typescript
initCamera方法通过创建相机管理器实例cameraMgr来创建画面输出对象previewOutput。cameraMgr再通过创建CaptureSession实例来配置会话,完成相机功能的准备工作。
import
image
from
'
@ohos.multimedia.image
'
;
//自@ohos.multimedia.image引入image,提供图片处理效果
..................
```
typescript
private
receiver
:
image
.
ImageReceiver
=
undefined
;
//图像接收类,用于获取组件surface id,接收最新的图片和读取下一张图片
import
image
from
'
@ohos.multimedia.image
'
;
//自@ohos.multimedia.image引入image,提供图片处理效果
..................
...
constructor
()
{
private
receiver
:
image
.
ImageReceiver
=
undefined
;
//图像接收类,用于获取组件surface id,接收最新的图片和读取下一张图片
this
.
mediaModel
=
MediaModel
.
getMediaInstance
();
//通过调用model/MediaModel.ets中的方法创建mediaInstance类mediaModel
...
//创建ImageReceiver实例receiver
constructor
()
{
this
.
receiver
=
image
.
createImageReceiver
(
this
.
mediaModel
=
MediaModel
.
getMediaInstance
();
//通过调用model/MediaModel.ets中的方法创建mediaInstance类mediaModel
cameraWH
.
width
,
//创建ImageReceiver实例receiver
cameraWH
.
height
,
this
.
receiver
=
image
.
createImageReceiver
(
FOUR
,
cameraWH
.
width
,
EIGHT
cameraWH
.
height
,
);
FOUR
,
//接收图片时注册回调
EIGHT
this
.
receiver
.
on
(
'
imageArrival
'
,
()
=>
{
);
//从ImageReceiver读取下一张图片
//接收图片时注册回调
this
.
receiver
.
readNextImage
((
err
,
image
)
=>
{
this
.
receiver
.
on
(
'
imageArrival
'
,
()
=>
{
if
(
err
||
image
===
undefined
)
{
//从ImageReceiver读取下一张图片
return
;
this
.
receiver
.
readNextImage
((
err
,
image
)
=>
{
}
if
(
err
||
image
===
undefined
)
{
//根据图像的组件类型从图像中获取组件缓存
return
;
image
.
getComponent
(
FOUR
,
(
errMsg
,
img
)
=>
{
}
if
(
errMsg
||
img
===
undefined
)
{
//根据图像的组件类型从图像中获取组件缓存
return
;
image
.
getComponent
(
FOUR
,
(
errMsg
,
img
)
=>
{
}
if
(
errMsg
||
img
===
undefined
)
{
let
buffer
=
new
ArrayBuffer
(
FOUR_THOUSAND_AND_SIXTY_NINE
);
return
;
if
(
img
.
byteBuffer
)
{
}
buffer
=
img
.
byteBuffer
;
let
buffer
=
new
ArrayBuffer
(
FOUR_THOUSAND_AND_SIXTY_NINE
);
}
if
(
img
.
byteBuffer
)
{
this
.
saveImage
(
buffer
,
image
);
buffer
=
img
.
byteBuffer
;
});
}
});
this
.
saveImage
(
buffer
,
image
);
});
});
}
});
});
}
async
initCamera
(
surfaceId
:
string
):
Promise
<
void
>
{
..................
try
{
async
initCamera
(
surfaceId
:
string
):
Promise
<
void
>
{
this
.
cameraMgr
=
camera
.
getCameraManager
(
globalThis
.
cameraContext
);
//获取相机管理器实例
...
}
try
{
this
.
camerasArray
=
this
.
cameraMgr
.
getSupportedCameras
();
//获取支持指定的相机设备对象
this
.
cameraMgr
=
camera
.
getCameraManager
(
globalThis
.
cameraContext
);
//获取相机管理器实例
if
(
this
.
camerasArray
.
length
===
0
)
{
}
return
;
this
.
camerasArray
=
this
.
cameraMgr
.
getSupportedCameras
();
//获取支持指定的相机设备对象
}
if
(
this
.
camerasArray
.
length
===
0
)
{
let
mCamera
=
this
.
camerasArray
[
0
];
return
;
this
.
cameraInput
=
this
.
cameraMgr
.
createCameraInput
(
mCamera
);
}
this
.
cameraInput
.
open
();
let
mCamera
=
this
.
camerasArray
[
0
];
this
.
capability
=
this
.
cameraMgr
.
getSupportedOutputCapability
(
mCamera
);
//查询相机设备支持的输出能力
this
.
cameraInput
=
this
.
cameraMgr
.
createCameraInput
(
mCamera
);
let
previewProfile
=
this
.
capability
.
previewProfiles
[
0
];
this
.
cameraInput
.
open
();
//通过相机管理器创建预览输出对象
this
.
capability
=
this
.
cameraMgr
.
getSupportedOutputCapability
(
mCamera
);
//查询相机设备支持的输出能力
this
.
previewOutput
=
this
.
cameraMgr
.
createPreviewOutput
(
let
previewProfile
=
this
.
capability
.
previewProfiles
[
0
];
previewProfile
,
//通过相机管理器创建预览输出对象
surfaceId
//surfaceId从XComponent组件获取
this
.
previewOutput
=
this
.
cameraMgr
.
createPreviewOutput
(
);
previewProfile
,
let
rSurfaceId
=
await
this
.
receiver
.
getReceivingSurfaceId
();
//获取一个surface id供其他组件使用
surfaceId
//surfaceId从XComponent组件获取
let
photoProfile
=
this
.
capability
.
photoProfiles
[
0
];
);
//通过相机管理器创建照片输出对象
let
rSurfaceId
=
await
this
.
receiver
.
getReceivingSurfaceId
();
//获取一个surface id供其他组件使用
this
.
photoOutPut
=
this
.
cameraMgr
.
createPhotoOutput
(
let
photoProfile
=
this
.
capability
.
photoProfiles
[
0
];
photoProfile
,
//通过相机管理器创建照片输出对象
rSurfaceId
//rSurfaceId通过构造函数中定义的图像接收类receiver获取
this
.
photoOutPut
=
this
.
cameraMgr
.
createPhotoOutput
(
);
photoProfile
,
this
.
capSession
=
this
.
cameraMgr
.
createCaptureSession
();
//创建CaptureSession实例
rSurfaceId
//rSurfaceId通过构造函数中定义的图像接收类receiver获取
this
.
capSession
.
beginConfig
();
//开始配置会话
);
this
.
capSession
.
addInput
(
this
.
cameraInput
);
//将cameraInput加入会话
this
.
capSession
=
this
.
cameraMgr
.
createCaptureSession
();
//创建CaptureSession实例
this
.
capSession
.
addOutput
(
this
.
previewOutput
);
//将预览输出加入会话
this
.
capSession
.
beginConfig
();
//开始配置会话
this
.
capSession
.
addOutput
(
this
.
photoOutPut
);
//将照片输出加入会话
this
.
capSession
.
addInput
(
this
.
cameraInput
);
//将cameraInput加入会话
await
this
.
capSession
.
commitConfig
();
//提交配置信息
this
.
capSession
.
addOutput
(
this
.
previewOutput
);
//将预览输出加入会话
await
this
.
capSession
.
start
();
//开始输出
this
.
capSession
.
addOutput
(
this
.
photoOutPut
);
//将照片输出加入会话
}
await
this
.
capSession
.
commitConfig
();
//提交配置信息
await
this
.
capSession
.
start
();
//开始输出
```
}
4.
点击按钮进行拍照
```
```
typescript
4.
点击按钮进行拍照
Image
(
this
.
getCameraIcon
())
.
size
({
width
:
64
,
height
:
64
})
拍照按钮通过Image组件呈现,其绑定的onClick方法调用takePicture方法开始拍照。
.
margin
({
left
:
10
})
.
id
(
'
camera
'
)
```
typescript
.
onClick
(()
=>
{
Image
(
this
.
getCameraIcon
())
if
(
this
.
currentModel
===
CameraMode
.
modePhoto
)
{
.
size
({
width
:
64
,
height
:
64
})
prompt
.
showToast
({
message
:
'
拍照中...
'
,
duration
:
200
});
.
margin
({
left
:
10
})
this
.
cameraModel
.
takePicture
();
//调用model/cameraModel.takePicture()开始拍照
.
id
(
'
camera
'
)
}
.
onClick
(()
=>
{
})
if
(
this
.
currentModel
===
CameraMode
.
modePhoto
)
{
```
prompt
.
showToast
({
message
:
'
拍照中...
'
,
duration
:
200
});
this
.
cameraModel
.
takePicture
();
//调用model/cameraModel.takePicture()开始拍照
5.
拍照功能具体实现
}
})
-
拍照
```
```
typescript
5.
拍照功能具体实现
async
takePicture
():
Promise
<
void
>
{
//设置拍照相关参数
-
拍照
let
photoSettings
=
{
rotation
:
this
.
imageRotation
,
```typescript
quality
:
camera
.
QualityLevel
.
QUALITY_LEVEL_MEDIUM
,
async takePicture(): Promise<void> {
location
:
{
//设置拍照相关参数
// 位置信息,经纬度
let photoSettings = {
latitude
:
12.9698
,
rotation: this.imageRotation,
longitude
:
77.75
,
quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
altitude
:
1000
,
location: {
},
// 位置信息,经纬度
mirror
:
false
,
latitude: 12.9698,
};
longitude: 77.75,
await
this
.
photoOutPut
.
capture
(
photoSettings
);
altitude: 1000,
AppStorage
.
Set
(
'
isRefresh
'
,
true
);
},
}
mirror: false,
```
};
await this.photoOutPut.capture(photoSettings);
-
保存图片
AppStorage.Set('isRefresh', true);
}
```
typescript
```
..................
//model/MediaModel.ts中定义的负责保存图片的相关方法
async
createAndGetUri
(
mediaType
:
mediaLibrary
.
MediaType
):
Promise
<
mediaLibrary
.
FileAsset
>
{
-
保存图片
let
dateTimeUtil
:
DateTimeUtil
=
new
DateTimeUtil
();
let
info
:
FileInfo
=
this
.
getInfoFromMediaType
(
mediaType
);
saveImage方法使用MediaModel中的createAndGetUri方法创建Image类型资源,将拍摄到的照片写入到这个资源中去。
let
name
:
string
=
`
${
dateTimeUtil
.
getDate
()}
_
${
dateTimeUtil
.
getTime
()}
`
;
//获取当前时间
let
displayName
:
string
=
`
${
info
.
prefix
}${
name
}${
info
.
suffix
}
`
;
```typescript
//获取公共目录路径。
//model/MediaModel.ts中定义的负责保存图片的相关方法
let
publicPath
:
string
=
await
this
.
mediaLibraryTest
.
getPublicDirectory
(
async createAndGetUri(mediaType: mediaLibrary.MediaType): Promise<mediaLibrary.FileAsset> {
info
.
directory
let dateTimeUtil: DateTimeUtil = new DateTimeUtil();
);
//通过引用自@ohos.multimedia.mediaLibrary的mediaLibraryTest类创建媒体资源,其中定义了媒体类型、名称、路径。
let info: FileInfo = this.getInfoFromMediaType(mediaType);
let
fileAsset
:
mediaLibrary
.
FileAsset
=
await
this
.
mediaLibraryTest
.
createAsset
(
let name: string = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`;//获取当前时间
mediaType
,
//根据传入函数createAndGetUri的mediaType参数决定创建什么类型的媒体资源
let displayName: string = `${info.prefix}${name}${info.suffix}`;
displayName
,
//获取公共目录路径。
publicPath
let publicPath: string = await this.mediaLibraryTest.getPublicDirectory(
);
info.directory
return
fileAsset
;
);//通过引用自@ohos.multimedia.mediaLibrary的mediaLibraryTest类创建媒体资源,其中定义了媒体类型、名称、路径。
}
let fileAsset: mediaLibrary.FileAsset = await this.mediaLibraryTest.createAsset(
async
getFdPath
(
fileAsset
:
mediaLibrary
.
FileAsset
):
Promise
<
number
>
{
mediaType,//根据传入函数createAndGetUri的mediaType参数决定创建什么类型的媒体资源
let
fd
:
number
=
await
fileAsset
.
open
(
'
Rw
'
);
//打开当前文件
displayName,
return
fd
;
publicPath
}
);
..................
return fileAsset;
}
async
saveImage
(
buffer
:
ArrayBuffer
,
img
:
image
.
Image
):
Promise
<
void
>
{
async getFdPath(fileAsset: mediaLibrary.FileAsset): Promise<number> {
this
.
fileAsset
=
await
this
.
mediaModel
.
createAndGetUri
(
mediaLibrary
.
MediaType
.
IMAGE
);
let fd: number = await fileAsset.open('Rw');//打开当前文件
//通过调用MediaModel中的方法创建Image类型资源
return fd;
this
.
photoPath
=
this
.
fileAsset
.
uri
;
}
this
.
fd
=
await
this
.
mediaModel
.
getFdPath
(
this
.
fileAsset
);
...
await
fileIo
.
write
(
this
.
fd
,
buffer
);
//将拍摄的照片写入到Mediamodel传回的资源中去
await
this
.
fileAsset
.
close
(
this
.
fd
);
//释放open函数
async saveImage(buffer: ArrayBuffer, img: image.Image): Promise<void> {
await
img
.
release
();
this.fileAsset = await this.mediaModel.createAndGetUri(mediaLibrary.MediaType.IMAGE);
if
(
this
.
takePictureHandle
)
{
//通过调用MediaModel中的方法创建Image类型资源
this
.
takePictureHandle
(
this
.
photoPath
);
this.photoPath = this.fileAsset.uri;
}
this.fd = await this.mediaModel.getFdPath(this.fileAsset);
}
await fileIo.write(this.fd, buffer);//将拍摄的照片写入到Mediamodel传回的资源中去
```
await this.fileAsset.close(this.fd);//释放open函数
await img.release();
if (this.takePictureHandle) {
this.takePictureHandle(this.photoPath);
}
}
```
## 全部代码
## 全部代码
...
@@ -242,7 +250,8 @@ Image(this.getCameraIcon())
...
@@ -242,7 +250,8 @@ Image(this.getCameraIcon())
## 参考
## 参考
[
权限列表
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync
)
-
[
权限列表
](
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/security/permission-list.md#ohospermissiondistributed_datasync
)
-
[
@ohos.multimedia.camera
](
../application-dev/reference/apis/js-apis-camera.md
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录