zoukankan      html  css  js  c++  java
  • 鸿蒙软总线跨设备访问该怎么玩——小总结

    目录:

    1、跨设备启动FA、跨设备迁移、回迁

    2、跨设备连接Service

    3、更多文章

    鸿蒙软总线跨设备访问该怎么玩——小总结

     重点撸代码:


    1、跨设备启动FA、跨设备迁移、回迁

    (1)权限

    ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE:用于允许监听分布式组网内的设备状态变化。
    ohos.permission.GET_DISTRIBUTED_DEVICE_INFO:用于允许获取分布式组网内的设备列表和设备信息。
    ohos.permission.GET_BUNDLE_INFO:用于查询其他应用的信息。
    ohos.permission.DISTRIBUTED_DATASYNC:用于允许不同设备间的数据交换。
    
    "reqPermissions": [
        {"name": "ohos.permission.DISTRIBUTED_DATASYNC"},
        {"name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"}, 
        {"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO" }, 
       {"name": "ohos.permission.GET_BUNDLE_INFO"} 
    ]
    
    //主动申明,要多设备协同,让用户选择允许还是禁止
    requestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0);

    (2)界面:ability_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <DirectionalLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:orientation="vertical">
    
        <Button
            ohos:id="$+id:main_start_fa_btn"
            ohos:height="match_content"
            ohos:width="300vp"
            ohos:text="1.启动远程设备的FA"
            ohos:text_size="20fp"
            ohos:text_color="#ffffff"
            ohos:background_element="$graphic:button_bg"
            ohos:layout_alignment="horizontal_center"
            ohos:top_padding="8vp"
            ohos:bottom_padding="8vp"
            ohos:left_padding="40vp"
            ohos:right_padding="40vp"
            ohos:top_margin="20vp"
            />
    
        <Button
            ohos:id="$+id:main_migration_btn"
            ohos:height="match_content"
            ohos:width="300vp"
            ohos:text="2.迁移到远程设备"
            ohos:text_size="20fp"
            ohos:text_color="#ffffff"
            ohos:background_element="$graphic:button_bg"
            ohos:layout_alignment="horizontal_center"
            ohos:top_padding="8vp"
            ohos:bottom_padding="8vp"
            ohos:left_padding="40vp"
            ohos:right_padding="40vp"
            ohos:top_margin="20vp"
            />
        
    </DirectionalLayout>

    button_bg.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape  xmlns:ohos="http://schemas.huawei.com/res/ohos"
            ohos:shape="rectangle">
        <solid ohos:color="#007DFF"/>
        <corners ohos:radius="40"/>
    </shape>

    另外我们需要的Page Abiltiy:MigrationAbility、RemoveAbility
     
    MainAbilitySlice:

    public class MainAbilitySlice extends AbilitySlice {
       private Button mainStartFABtn,mainMigrationBtn;
    
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            mainStartFABtn = (Button)findComponentById(ResourceTable.Id_main_start_fa_btn);
            mainMigrationBtn = (Button)findComponentById(ResourceTable.Id_main_migration_btn);
            
            mainStartFABtn.setClickedListener(mClickListener);
            mainMigrationBtn.setClickedListener(mClickListener);
        }
    
        private Component.ClickedListener mClickListener = new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                int compoentId = component.getId();
                switch (compoentId){
                    case ResourceTable.Id_main_start_fa_btn:
                        //点击后跨设备打开Fa
                        //第一种写法
                        Intent intent = new Intent();
                        Operation op = new Intent.OperationBuilder()
                                .withDeviceId(Common.getOnLineDeviceId())
                                .withBundleName("com.ybzy.demo")
                                .withAbilityName("com.ybzy.demo.RemoveAbility")
                                .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                                .build();
                        intent.setOperation(op);
                        intent.setParam("msg","我夸设备把你这个FA拉起来了!");
                        startAbility(intent);
    
                        //第二钟写法
                        intent.setElement(new ElementName(Common.getOnLineDeviceId()
                                                ,"com.ybzy.demo","com.ybzy.demo.RemoveAbility"));
                        intent.setFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE);
                        intent.setParam("msg","我夸设备把你这个FA拉起来了!");
                        startAbility(intent);
    
                        break;
                    case ResourceTable.Id_main_migration_btn:
                        //点击后进入要迁移的Ability页面
                        Intent migrationIntent = new Intent();
                        migrationIntent.setElement(new ElementName("","com.ybzy.demo"
                                                        ,"com.ybzy.demo.MigrationAbility"));
                        startAbility(migrationIntent);
                        break;
                    default:
                        break;
                }
            }
        };
    
        @Override
        public void onActive() {
            super.onActive();
        }
    
        @Override
        public void onForeground(Intent intent) {
            super.onForeground(intent);
        }
    }

    ability_migration.xml

    <?xml version="1.0" encoding="utf-8"?>
    <DirectionalLayout
        xmlns:ohos="http://schemas.huawei.com/res/ohos"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:background_element="#00ffff"
        ohos:orientation="vertical">
    
        <Text
            ohos:id="$+id:migration_text"
            ohos:height="match_content"
            ohos:width="250vp"
            ohos:background_element="#0088bb"
            ohos:layout_alignment="horizontal_center"
            ohos:text="下面是一个可编辑的文本框"
            ohos:text_size="50"
            ohos:padding="5vp"
            ohos:top_margin="30vp"
            />
    
        <TextField
            ohos:id="$+id:migration_textfield"
            ohos:height="250vp"
            ohos:width="250vp"
            ohos:hint="请输入..."
            ohos:layout_alignment="horizontal_center"
            ohos:background_element="#ffffff"
            ohos:text_color="#888888"
            ohos:text_size="20fp"
            ohos:padding="5vp"
            />
        <Button
            ohos:id="$+id:migration_migration_btn"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="点击迁移"
            ohos:text_size="20fp"
            ohos:text_color="#ffffff"
            ohos:background_element="$graphic:button_bg"
            ohos:top_padding="8vp"
            ohos:bottom_padding="8vp"
            ohos:left_padding="50vp"
            ohos:right_padding="50vp"
            ohos:layout_alignment="horizontal_center"
            ohos:top_margin="30vp"
            />
    
        <Button
            ohos:id="$+id:migration_migration_back_btn"
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="点击迁移回来"
            ohos:text_size="20fp"
            ohos:text_color="#ffffff"
            ohos:background_element="$graphic:button_bg"
            ohos:top_padding="8vp"
            ohos:bottom_padding="8vp"
            ohos:left_padding="50vp"
            ohos:right_padding="50vp"
            ohos:layout_alignment="horizontal_center"
            ohos:top_margin="30vp"
            />
    </DirectionalLayout>

    RemoveAbility...把接收到的值显示到页面就行,setText()

    (3)工具类

    public class Common{
        public static String getDeviceId(){
            List<DeviceInfo> deviceList = DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ONLINE_DEVICE);
            if(deviceList.isEmpty()){
                return null;
            }
            int deviceNum = deviceList.size();
            List<String> deviceIds = new ArrayList<>(deviceNum);
            List<String> deviceNames = new ArrayList<>(deviceNum);
            deviceList.forEach((device)->{
                deviceIds.add(device.getDeviceId());
                deviceNames.add(device.getDeviceName());
            });
    
            //我们这里的实验环境,就两部手机,组件还没讲
            //我就直接使用deviceIds的第一个元素,做为启动远程设备的目标id
            String devcieIdStr = deviceIds.get(0);
            return devcieIdStr;
        }
    
    
        public static void myShowTip(Context context,String msg){
            //提示框的核心组件文本
            Text text = new Text(context);
            text.setWidth(MATCH_CONTENT);
            text.setHeight(MATCH_CONTENT);
            text.setTextSize(16, Text.TextSizeType.FP);
            text.setText(msg);
            text.setPadding(30,20,30,20);
            text.setMultipleLine(true);
            text.setMarginLeft(30);
            text.setMarginRight(30);
            text.setTextColor(Color.WHITE);
            text.setTextAlignment(TextAlignment.CENTER);
        
            //给上面的文本设置一个背景样式
            ShapeElement style = new ShapeElement();
            style.setShape(ShapeElement.RECTANGLE);
            style.setRgbColor(new RgbColor(77,77,77));
            style.setCornerRadius(15);
            text.setBackground(style);
        
            //构建存放上面的text的布局
            DirectionalLayout mainLayout = new DirectionalLayout(context);
            mainLayout.setWidth(MATCH_PARENT);
            mainLayout.setHeight(MATCH_CONTENT);
            mainLayout.setAlignment(LayoutAlignment.CENTER);
            mainLayout.addComponent(text);
        
            //最后要让上面的组件绑定dialog
            ToastDialog toastDialog = new ToastDialog(context);
            toastDialog.setSize(MATCH_PARENT,MATCH_CONTENT);
            toastDialog.setDuration(1500);
            toastDialog.setAutoClosable(true);
            toastDialog.setTransparent(true);
            toastDialog.setAlignment(LayoutAlignment.CENTER);
            toastDialog.setComponent((Component) mainLayout);
            toastDialog.show();
        }
        
    }

    (4)实现功能
    MigrationAbilitySlice:

    public class MigrationAbilitySlice extends AbilitySlice implements IAbilityContinuation {
        TextField migrationTextField;
        Button migrationMigrationBtn,migrationMigrationBackBtn;
        String msg = "";
    
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_migration);
    
            migrationTextField = (TextField)findComponentById(ResourceTable.Id_migration_textfield);
            migrationTextField.setText(msg);
            migrationMigrationBtn = (Button)findComponentById(ResourceTable.Id_migration_migration_btn);
            migrationMigrationBtn.setClickedListener(component -> {
                //1、要进行迁移的Ability实现接口 IAbilityContinuation,实现的方法返回值改成true
                //2、要进行迁移的Ability下面关联的所有AbilitySlice都要实现接口 IAbilityContinuation,
                //  实现的方法上处理数据
                //3、进行迁移
                String deviceId = Common.getOnLineDeviceId();
                if(deviceId != null){
    //                continueAbility(deviceId); 
                    continueAbilityReversibly(deviceId);
                }
            });
    
            migrationMigrationBackBtn = (Button) findComponentById(ResourceTable
                                                                        .Id_migration_migration_back_btn);
            migrationMigrationBackBtn.setClickedListener(component -> {
                reverseContinueAbility();
            });
        }
    
        @Override
        public void onActive() {
            super.onActive();
        }
    
        @Override
        public void onForeground(Intent intent) {
            super.onForeground(intent);
        }
    
        @Override
        public boolean onStartContinuation() {
            return true;
        }
    
        @Override
        public boolean onSaveData(IntentParams intentParams) {
            intentParams.setParam("msg",migrationTextField.getText());
            return true;
        }
    
        @Override
        public boolean onRestoreData(IntentParams intentParams) {
            msg = intentParams.getParam("msg").toString();
    //        getUITaskDispatcher().asyncDispatch(() -> {
    //            migrationTextField.setText(intentParams.getParam("msg").toString());
    //        });
            return true;
        }
    
        @Override
        public void onCompleteContinuation(int i) {
    
        }
    
    }

    2、跨设备连接Service

    启动远程设备Service的代码示例如下:
    添加按钮:

    <Button
        ohos:id="$+id:main_start_removeService_btn"
        ohos:height="match_content"
        ohos:width="300vp"
        ohos:text="远程启动ServiceAbility"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        ohos:background_element="$graphic:button_bg"
        ohos:layout_alignment="horizontal_center"
        ohos:top_padding="8vp"
        ohos:bottom_padding="8vp"
        ohos:left_padding="40vp"
        ohos:right_padding="40vp"
        ohos:top_margin="20vp"
        />
        
        <Button
        ohos:id="$+id:main_stop_removeService_btn"
        ohos:height="match_content"
        ohos:width="300vp"
        ohos:text="远程关闭ServiceAbility"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        ohos:background_element="$graphic:button_bg"
        ohos:layout_alignment="horizontal_center"
        ohos:top_padding="8vp"
        ohos:bottom_padding="8vp"
        ohos:left_padding="40vp"
        ohos:right_padding="40vp"
        ohos:top_margin="20vp"
        />

    新建RemoteServiceAbility:

    public class RemoteServiceAbility extends Ability {
        private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "Demo");
        private Source sVideoSource;
        private Player sPlayer;
    
        @Override
        public void onStart(Intent intent) {
            HiLog.error(LABEL_LOG, "RmoteServiceAbility::onStart");
            super.onStart(intent);
            Common.myShowTip(this,"remote onstart");
            sPlayer = new Player(RemoteServiceAbility.this);
            new PlayerThread().start();
        }
        class PlayerThread extends Thread {
            @Override
            public void run() {
                try {
                    File mp3FilePath = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
                    if (!mp3FilePath.exists()) {
                        mp3FilePath.mkdirs();
                    }
                    File mp3File = new File(mp3FilePath.getAbsolutePath() + "/" + "bj.mp3");
    
                    Resource res = getResourceManager()
                            .getRawFileEntry("resources/rawfile/bj.mp3").openRawFile();
                    byte[] buf = new byte[4096];
                    int count = 0;
                    FileOutputStream fos = new FileOutputStream(mp3File);
                    while ((count = res.read(buf)) != -1) {
                        fos.write(buf, 0, count);
                    }
                    FileDescriptor fileDescriptor = new FileInputStream(mp3File).getFD();
                    sVideoSource = new Source(fileDescriptor);
                    sPlayer.setSource(sVideoSource);
                    sPlayer.prepare();
                    sPlayer.setVolume(0.3f);
                    sPlayer.enableSingleLooping(true);
                    sPlayer.play();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        @Override
        public void onStop() {
            super.onStop();
            Common.myShowTip(RemoteServiceAbility.this,"remote onStop");
            sPlayer.stop();
        }
    
        @Override
        public IRemoteObject onConnect(Intent intent) {
            return null;
        }
        @Override
        public void onDisconnect(Intent intent) {
        }
    }

    启动:

    case ResourceTable.Id_main_start_remoteService_btn:
    
        Common.myShowTip(MainAbilitySlice.this,deviceId);
        Intent startRemoteServiceIntent = new Intent();
        startRemoteServiceIntent.setElement(new ElementName(
                deviceId,
                "com.ybzy.demo",
                "com.ybzy.demo.RemoteServiceAbility"
        ));
        startRemoteServiceIntent.setFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE);
        startAbility(startRemoteServiceIntent);
        break;
     

    关闭远程设备Service:

    case ResourceTable.Id_main_stop_remoteService_btn:
        Common.myShowTip(MainAbilitySlice.this,deviceId);
        Intent stopRemoteServiceIntent = new Intent();
        stopRemoteServiceIntent.setElement(new ElementName(
                deviceId,
                "com.ybzy.demo",
                "com.ybzy.demo.RemoteServiceAbility"
        ));
        stopRemoteServiceIntent.setFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE);
        stopAbility(stopRemoteServiceIntent);
        break;

    仅通过启动和停止Service Ability两种方式对Service进行调度无法应对需长期交互的场景,
    简单地说,信息就是只能去,回不来!
    因此,分布式任务调度平台向开发者提供了跨设备Service连接及断开连接的能力。
    链接上了,信息可去可回!
     
    链接是使用connectAbility()方法,需要传入目标Service的Intent与接口IAbilityConnection的实例对象。
     
    接口IAbilityConnection提供了两个方法供开发者实现:
    (1)onAbilityConnectDone()用来处理连接的回调。
    (2)onAbilityDisconnectDone()用来处理断开连接的回调。
     
    我们可以在onAbilityConnectDone()中获取管理链接的代理,进一步为了使用该代理跨设备调度Service,
    开发者需要在本地及远端分别实现对外接口一致的代理,这个接口是IRemoteBroker。
     
    添加按钮:

    <Button
        ohos:id="$+id:main_connect_remoteService_btn"
        ohos:height="match_content"
        ohos:width="300vp"
        ohos:text="远程链接ServiceAbility"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        ohos:background_element="$graphic:button_bg"
        ohos:layout_alignment="horizontal_center"
        ohos:top_padding="8vp"
        ohos:bottom_padding="8vp"
        ohos:left_padding="40vp"
        ohos:right_padding="40vp"
        ohos:top_margin="20vp"
        />
    
    <Button
        ohos:id="$+id:main_use_remoteService_btn"
        ohos:height="match_content"
        ohos:width="300vp"
        ohos:text="使用远程ServiceAbility"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        ohos:background_element="$graphic:button_bg"
        ohos:layout_alignment="horizontal_center"
        ohos:top_padding="8vp"
        ohos:bottom_padding="8vp"
        ohos:left_padding="40vp"
        ohos:right_padding="40vp"
        ohos:top_margin="20vp"
        />
    
    <Button
        ohos:id="$+id:main_disconnect_remoteService_btn"
        ohos:height="match_content"
        ohos:width="300vp"
        ohos:text="远程断开ServiceAbility"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        ohos:background_element="$graphic:button_bg"
        ohos:layout_alignment="horizontal_center"
        ohos:top_padding="8vp"
        ohos:bottom_padding="8vp"
        ohos:left_padding="40vp"
        ohos:right_padding="40vp"
        ohos:top_margin="20vp"
        />

    发起连接的本地侧的代理示例如下:

    public class MyRemoteProxy implements IRemoteBroker {
        //IRemoteBroker:获取远程代理对象的持有者
        private static final int ERR_OK = 0;
        //COMMAND_PLUS表示有效消息进行通信的约定的标记,MIN_TRANSACTION_ID是这个标记可以用的最小值:1
        private static final int COMMAND_PLUS = IRemoteObject.MIN_TRANSACTION_ID;
    
        //IRemoteObject:此接口
        // 可用于查询或获取接口描述符、
        // 添加或删除死亡通知、
        // 将对象状态转储到特定文件以及发送消息。
        private final IRemoteObject remote;
        public MyRemoteProxy(IRemoteObject remote) {
            this.remote = remote;
        }
    
        @Override
        public IRemoteObject asObject() {//获取远程代理对象的方法
            return remote;
        }
    
        public int plus(int a,int b) throws RemoteException {
            //MessageParcel:这个类提供了读写对象、接口标记、文件描述符和大数据的方法。
            MessageParcel data = MessageParcel.obtain();
            //obtain()创建索引为0的空MessageParcel对象
            MessageParcel reply = MessageParcel.obtain();
    
            //MessageOption:定义与sendRequest一起发送消息的选项。
            // option不同的取值,决定采用同步或异步方式跨设备调用Service
            // 这个例子我们需要同步获取对端Service执行加法运算后的结果,同步模式调用sendRequest接口,即MessageOption.TF_SYNC
            // 对应的是异步:TF_ASYNC
            MessageOption option = new MessageOption(MessageOption.TF_SYNC);
            data.writeInt(a);
            data.writeInt(b);
    
            try {
                remote.sendRequest(COMMAND_PLUS, data, reply, option);
                //第1个参数:约定通信双方确定的消息标记。
                //第2个参数:发送到对等端侧的数据包裹MessageParcel对象。
                //第3个参数:对等端侧返回的数据包裹MessageParcel对象。
                //第4个参数:设置发送消息,用同步还是异步模式。
                int ec = reply.readInt(); //返回通信成不成功,约定的标记ERR_OK
                if (ec != ERR_OK) {
                    throw new RemoteException();
                }
                int result = reply.readInt();
                return result;
            } catch (RemoteException e) {
                throw new RemoteException();
            } finally {
                data.reclaim(); //reclaim()清除不再使用的MessageParcel对象。
                reply.reclaim();
            }
        }
    }

    等待连接的远端侧的代理示例如下:

    public class MyRemote extends RemoteObject implements IRemoteBroker{
        private static final int ERR_OK = 0;
        private static final int ERROR = -1;
        private static final int COMMAND_PLUS = IRemoteObject.MIN_TRANSACTION_ID;
     
        public MyRemote() {
            super("MyService_Remote");
        }
     
        @Override
        public IRemoteObject asObject() {
            return this;
        }
     
        @Override
        public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
            if (code != COMMAND_PLUS) {
                reply.writeInt(ERROR);
                return false;
            }
            int value1 = data.readInt();
            int value2 = data.readInt();
            int sum = value1 + value2;
            reply.writeInt(ERR_OK);
            reply.writeInt(sum);
            return true;
        }
    }

    等待连接侧还需要作如下修改:

    // 绑定前面定义的代理,实例化出发起链接侧需要的代理
    private MyRemote remote = new MyRemote();
    @Override
    public IRemoteObject onConnect(Intent intent) {
        //链接成功的时候,给发起链接侧返回去
        return remote.asObject();
    }

    完成上述步骤后,可以通过点击事件实现连接、利用连接关系控制PA以及断开连接等行为,代码示例如下:

    private MyRemoteProxy mProxy = null;
    // 创建连接回调实例
    private IAbilityConnection conn = new IAbilityConnection() {
        // 连接到Service的回调
        @Override
        public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int resultCode) {
            // 在这里开发者可以拿到服务端传过来IRemoteObject对象,从中解析出服务端传过来的信息
            mProxy = new MyRemoteProxy(iRemoteObject);
            UIUtils.showTip(MainAbilitySlice.this,"拿到remoteObject:" + mProxy);
        }
    
        // 意外断开连接才会回调
        @Override
        public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
        }
    };
    
    
    
    // 连接远程
    case ResourceTable.Id_main_connect_remoteService_btn:
        //1、实现连接的本地侧的代理
        //2、实现等待连接的远端侧的代理
        //3、修改等待连接侧的Service
        //4、在本地(发起链接侧)获取远端(被链接侧)返回过来的链接代理,创建链接后的回调函数
        //5、实现链接,通过代理对象使用Service的服务
        if (deviceId != null) {
            Intent connectServiceIntent = new Intent();
            connectServiceIntent.setElement(new ElementName(
                    deviceId,
                    "com.ybzy.demo",
                    "com.ybzy.demo.RemoteServiceAbility"
            ));
            connectServiceIntent.setFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE);
            connectAbility(connectServiceIntent, iAbilityConnection);
        }
        break;
        
        
    // 链接后使用
    case ResourceTable.Id_main_use_remoteService_btn:
        if (mProxy != null) {
            int ret = -1;
            try {
                ret = mProxy.plus(10, 20);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Common.myShowTip(MainAbilitySlice.this, "获取的结果:" + ret);
        }
        break;
        
    // 用完断开
    case ResourceTable.Id_main_disconnect_remoteService_btn:
        disconnectAbility(iAbilityConnection);
        break;

    作者:zhonghongfa

    想了解更多内容,请访问51CTO和华为合作共建的鸿蒙社区:https://harmonyos.51cto.com

  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/HarmonyOS/p/14577967.html
Copyright © 2011-2022 走看看