微信小程序和抖音小程序的分享和广告接入代码

微信小程序接入广告 小程序的广告功能如果用好,还是有比较可观的收入的,我的小程序就集成了这些广告,如果您想先看一下广告的所有样式展示,可以在微信小程序搜“AI妙笔生图”先睹为快,或者直接扫下面的小程序码也可以,码字不易,如您愿意,别忘了在小程序里点个广告,看个广告再走哦,小女子感激不尽。这样就打开激励视频了,可是我们还需要知道用户是否看完了视频,还是在未看完就点了关闭,这就需要回调来进行判断,将下面的代码贴到onload里,当然你也可以像我一样独立写个方法。我开通了Banner广告,激励广告,插屏广告,视频广告,和封面广告。 阅读详情
AI摘要

开发小程序或小游戏后,接入分享和广告功能可实现用户获取与增长、增强用户互动、商业变现。文章讲解了微信和抖音小程序分享功能及广告接入的代码设置,如微信在页面逻辑设分享、接入广告组件等,还整合了满足多平台要求的工具类。

开发完成小程序或者小游戏之后,我们为什么要接入分享和广告视频功能,主要原因有以下几个方面。

微信小程序和抖音小程序接入分享和广告功能主要基于以下几个原因:

  1. 用户获取与增长:分享功能可以帮助用户将小程序内容传播给更多人,从而扩大用户基础。通过社交网络的分享,能够吸引更多潜在用户使用小程序。

  2. 增强用户互动:分享功能可以提升用户之间的互动,增加用户粘性。用户在分享内容时,往往会带来新的使用场景和体验,这样可以促进用户的积极参与。

  3. 商业变现:广告功能为小程序提供了一种商业变现的方式。通过广告,开发者可以获得收入,从而支持小程序的持续运营与发展。

目前大部分小程序和小游戏都是靠广告变现,所以接入广告的代码是所有开发者必不可少的环节了,下面给大家讲解一下如何加入分享和广告接入的代码。

文章最后整合了一个工具类,有需要的朋友可以直接复制使用.

微信小程序

分享功能
  1. 在页面逻辑中设置分享:

  • 在小程序的页面代码中,使用 onShareAppMessage 函数设置分享内容:

  • 
    Page({  
      onShareAppMessage: function () {  
        return {  
          title: '分享标题',  
          path: '/pages/example/example?id=123',  
          imageUrl: '/images/share.png' // 可选  
        };  
      }  
    });

    2. 用户触发分享:

  • 可以在页面中添加一个分享按钮,使用 wx.showShareMenu 显示分享菜单:

  • 
    wx.showShareMenu({  
      withShareTicket: true // 可选,是否使用带分享票据的分享  
    });
    广告接入
  • 1,接入广告组件:
    • 在小程序的页面中引入广告组件,例如 banner 广告:

    • 
      <ad unit-id="你的广告位ID" />

      由于广告目前是各大平台的主要收入来源,所以微信和抖音都是花了很大的力气让开发者尽可能地简单接入广告代码。就这样一句代码,加到你的小程序里面,他就会源源不断地输送广告。

    • 输送的广告完全是依靠大数据,你喜欢看什么,就给你推什么广告。

        

2,初始化广告:

  • 在对应的 JavaScript 文件中,您可以监控广告加载事件:

  • 
    const adInstance = wx.createBannerAd({  
      adUnitId: '你的广告位ID',  
      style: {  
        left: 0,  
        top: 0,  
        width: 300  
      }  
    });  
    
    adInstance.onLoad(() => {  
      console.log('广告加载成功');  
    });  
    
    adInstance.onError((err) => {  
      console.error('广告加载失败', err);  
    });

    抖音小程序

    分享功能
  • 在页面中设置分享行为:

    • 在 页面 的 JS 文件中,使用 onShareAppMessage:

    • 
      Page({  
        onShareAppMessage: function () {  
          return {  
            title: '抖音小程序分享',   
            path: '/pages/example/example?id=123',  
          };  
        }  
      });

      2.主动分享:

    • 通过按钮或其他触发事件调用 my.share 方法:

    • 
      my.share({  
        title: '分享标题',  
        url: '分享链接',  
        success: (result) => {  
          console.log(result);  
        },  
        fail: (error) => {  
          console.error(error);  
        }  
      });
      广告接入
    • 引入广告组件:

      • 在页面的 HTML 代码中添加广告组件:

      • 
        <ad unit-id="你的广告位ID" />

        广告初始化和监控:

        通过 JavaScript 控制广告的加载和监控

      • const ad = my.createBannerAd({  
          adUnitId: '你的广告位ID',  
          style: {  
            top: 0,  
            left: 0,  
            width: '100%',  
          },  
        });  
        
        ad.onLoad(() => {  
          console.log('广告加载成功');  
        });  
        
        ad.onError((err) => {  
          console.error('广告加载失败', err);  
        });

虽然看起来非常简单,但是实际上开发起来还是不方便,所以我写了一套完整的小游戏开发的工具类,满足了各大平台的要求.包括登录,分享,插屏广告,激励广告,banner广告,抖音侧边栏功能.

/**
 * 小游戏平台SDK工具封装,目前只支持微信和抖音平台
 */
export namespace MiniGameSdk {

    interface ISize {
        width: number;
        height: number;
    }

    export interface IPosition {
        top: number;
        left: number;
    }

    export function isWechat(): boolean {
        //@ts-ignore
        return window.wx !== null && window.wx !== undefined;
    }

    export function isBytedance(): boolean {
        //@ts-ignore
        return window.tt !== null && window.tt !== undefined;
    }

    // 支付宝平台
    export function isAli(): boolean {
        //@ts-ignore
        return window.my !== null && window.my !== undefined;
    }

    function getSysWinSize(): ISize {
        let sys: any;
        if (isWechat()) {
            // @ts-ignore
            sys = wx.getSystemInfoSync();
        } else if (isBytedance()) {
            // @ts-ignore
            sys = tt.getSystemInfoSync();
        }

        let size: ISize = { width: 0, height: 0 };
        if (sys) {
            size.width = sys.windowWidth;
            size.height = sys.windowHeight;
        }

        return size;
    }

    /**
     * 插屏广告。微信抖音都支持!
     */
    class ADInterstitial {
        private _adUid: string;
        private _interstitial: any;

        get aduid() {
            return this._adUid;
        }

        constructor(adUid: string) {
            this._adUid = adUid;
        }

        show() {
            // @ts-ignore
            if (isWechat() && !wx.createInterstitialAd) {
                console.warn('wechat unsupport interstitial AD!');
                this._interstitial = null;
                return;
            }

            // @ts-ignore
            if (isBytedance() && !tt.createInterstitialAd) {
                console.warn('bytedance unsupport interstitial AD!');
                this._interstitial = null;
                return;
            }


            if (this._interstitial) {
                this._interstitial.load();
            } else {
                if (isWechat()) {
                    // @ts-ignore
                    this._interstitial = wx.createInterstitialAd({ adUnitId: this._adUid });
                } else if (isBytedance()) {
                    // @ts-ignore
                    this._interstitial = tt.createInterstitialAd({ adUnitId: this._adUid });
                } else {
                    this._interstitial = null;
                }

                this._interstitial?.onLoad(() => {
                    console.log('load interstitial ad success');
                    this._interstitial.show().catch((err: any) => {
                        console.log('catch interstitial ad error:', err);
                    });
                });

                this._interstitial?.onError((err: any) => {
                    console.log('interstitial ad on error:', err);
                });
            }
        }
        destory() {
            this._interstitial?.destroy();
        }
    }

    class ADBanner {
        private _adUid: string;
        private _banner: any;

        get aduid() {
            return this._adUid;
        }

        /**
         * 抖音和微信都支持
         * 横幅广告。预估宽度默认为300,预估高度为140。如果你不确定就按默认值来。
         * @param adUid 广告UID,后端配置
         * @param isTop 是否在屏幕顶部展示。内部会自动居中计算位置。
         * @param bannerWidth 横幅广告的预估宽度。默认300
         * @param autoShow 广告加载完成后是否立刻显示,默认为不显示
         */
        constructor(adUid: string, param: boolean | IPosition, bannerWidth: number = 300, autoShow: boolean = false) {
            this._adUid = adUid;
            this.create(autoShow, bannerWidth, param); // 默认300比较合适
        }

        private create(autoShow: boolean, bannerWidth: number, param: boolean | IPosition) {
            if (!isWechat() && !isBytedance()) {
                this._banner = null;
                return;
            }

            this.destroy();

            let winSize = getSysWinSize();

            let height = bannerWidth * 0.4;
            let top = 0, left = 0;

            if (typeof param === "boolean") {
                left = (winSize.width - bannerWidth) / 2
                top = param ? 5 : (winSize.height - height);
            } else {
                left = param.left;
                top = param.top;
            }

            let params = {
                adUnitId: this._adUid,
                adIntervals: 30,// 自动刷新频率不能小于30秒
                style: { left: left, top: top, width: bannerWidth }
            }

            if (isWechat()) {
                // @ts-ignore
                this._banner = wx.createBannerAd(params);
            } else if (isBytedance()) {
                // @ts-ignore
                this._banner = tt.createBannerAd(params);
            } else {
                this._banner = null;
            }

            this._banner?.onError((err: any) => {
                console.log('ad banner error:', err);
            });

            this._banner?.onLoad(() => {
                autoShow && this._banner.show();
            });
        }

        show() {
            this._banner?.show();
        }

        hide() {
            this._banner?.hide();
        }

        destroy() {
            this._banner?.destroy();
        }
    }

    class ADCustom {
        private _adUid: string;
        private _adCustom: any;

        get aduid() {
            return this._adUid;
        }
        /**
         * 由于原生模板广告在微信服务后端可以定制宽度大小,个数,缩放比例等,所以位置调整要根据设置的宽度来定。抖音不支持!
         * @param adUid 广告UID,后端配置
         * @param top 从左上角开始,距离屏幕顶部的距离。注意:这个数据为设备屏幕宽度width。如果需要获取屏幕的像素,需要乘以设备像素比Pixel-Ratio,例如iPhone 13 Pro的Pixel-Ratio为3,像素为Width*3。
         * @param left 从左上角开始,距离屏幕最左边的距离。注意:这个数据为设备屏幕宽度width。如果需要获取屏幕的像素,需要乘以设备像素比Pixel-Ratio,例如iPhone 13 Pro的Pixel-Ratio为3,像素为Width*3。
         * @param scale 原生模板广告的尺寸,默认为1,即100%。此值在微信服务后端广告中获得,默认为100%,目前有100%,90%,80%三种,一般情况不用修改。若有修改,记得传入值,例如90%就传入0.9。
         */
        constructor(adUid: string, top: number = 0, left: number = 0, scale: number = 1.0) {
            this._adUid = adUid;
            this.createCustomAd(top, left, scale);
        }

        private createCustomAd(top: number, left: number, scale: number) {
            if (!isWechat()) { // only wechat support custom ad
                this._adCustom = null;
                console.log('Only wechat support Custom Ad');
                return;
            }

            this.destroy();
            // 原生模板5个应用宽度为375,若设置了缩放比例,则宽度也需要设置
            // let width = 375 * this._scale;
            // let newLeft = (sys.windowWidth - width) / 2;
            // let newTop = sys.windowHeight / 2; // 120是预估高度

            // @ts-ignore
            this._adCustom = wx.createCustomAd({
                adUnitId: this._adUid,
                style: { left: left, top: top, fixed: true }
            });

            this._adCustom?.onError((err: any) => {
                console.log('ad custom error:', err);
            });
        }
        show() {
            this._adCustom?.show();
        }

        hide() {
            this._adCustom?.hide();
        }

        destroy() {
            this._adCustom?.destroy();
        }
    }


    /**
     * 视频广告用户点击行为结果
     */
    export enum EAdVideoResult {
        /**
         * 用户看完了广告,游戏可发放奖励。
         */
        ACCEPT,

        /**
         * 用户中途关闭了广告,即未看完状态。不可发放奖励。
         */
        REJECT,

        /**
         * 广告组件内部发生了错误。不可发放奖励。
         */
        ERROR,
    }

    class ADVideo {
        private _adUid: string;
        private _adVideo: any = null;

        get aduid() {
            return this._adUid;
        }

        constructor(adUid: string) {
            this._adUid = adUid;
        }

        /**
         * 由于微信和抖音视频广告机制不同,微信可以看的视频广告个数只有0和1个,抖音平台则可以看0~maxVideoCount
         * @param onResult 两个参数:第一个res是EAdVideoResult定义,第二count是用户看了多少个视频广告。
         * @param target onResult的拥有者
         * @param maxVideoCount 可以连续看最大视频个数,可最大化商业效率。默认为3个。
         * @returns 
         */
        show(onResult: (res: EAdVideoResult, count: number) => void, target?: any, maxVideoCount: number = 3): void {
            let callback = (state: EAdVideoResult, count: number) => {
                onResult?.call(target, state, count);
            }

            if (!isWechat() && !isBytedance()) {
                callback(EAdVideoResult.ACCEPT, 1);
                this._adVideo = null;
                return;
            }

            let onAdVideoClosed = (res: any) => {
                this._adVideo?.offClose(onAdVideoClosed);
                if (isWechat()) {
                    if (res && res.isEnded || res === undefined) {
                        callback(EAdVideoResult.ACCEPT, 1);
                    } else {
                        callback(EAdVideoResult.REJECT, 0);
                    }
                } else if (isBytedance()) {
                    let resConverted = res as { isEnded: boolean, count: number };
                    if (resConverted && resConverted.count > 0) {
                        callback(EAdVideoResult.ACCEPT, resConverted.count);
                    } else {
                        callback(EAdVideoResult.REJECT, 0);
                    }
                }
            }

            this._adVideo?.offClose(onAdVideoClosed);

            if (isWechat()) {
                // @ts-ignore
                this._adVideo = wx.createRewardedVideoAd({
                    adUnitId: this._adUid
                });
            } else if (isBytedance()) {
                // @ts-ignore
                this._adVideo = tt.createRewardedVideoAd({
                    adUnitId: this._adUid,
                    multiton: true,
                    multitonRewardMsg: ['多1次奖励', '再多一次奖励', '再多一次奖励'],
                    multitonRewardTimes: maxVideoCount,
                });
            } else {
                this._adVideo = null;
            }



            this._adVideo?.onLoad(() => {
                console.log('Ad load success');
            });

            this._adVideo?.onError((err: { errMsg: string, errCode: number }) => {
                console.log('Ad video error:', err);
                callback(EAdVideoResult.ERROR, 0);
            });

            this._adVideo?.onClose(onAdVideoClosed);

            console.info("广告2");
            this._adVideo?.show().catch(() => {
                this._adVideo?.load().then(() =>
                    this._adVideo?.show()).catch((err: { errMsg: string, errCode: number }) => {
                        console.log('Catch video ad error:', err);
                        callback(EAdVideoResult.ERROR, 0);
                    });
            });
        }

        destory() {
            this._adVideo?.destory();
        }
    }

    export enum EAdBannerLocation {
        /**
         * 屏幕顶部
         */
        TOP,

        /**
         * 屏幕底部
         */
        BOTTOM,
    }

    export class AdvertManager {

        private static _instance: AdvertManager;

        static get instance(): AdvertManager {
            if (!AdvertManager._instance) {
                AdvertManager._instance = new AdvertManager();
            }
            return AdvertManager._instance;
        }

        private _video: ADVideo;
        private _interstitial: ADInterstitial;
        private _banner: ADBanner;
        private _customs: Record<string, ADCustom> = {};

        private constructor() {

        }

        /**
         * 预加载横幅广告,不会显示。只有你在调用showBanner时才会显示。
         * 可重复调用,但是会销毁上一次的实例。一般情况,全局有一个就行了,太多占用内存,而且没必要。
         * @param adUid 广告UID
         * @param location 位置有两种情况:1、可以传入枚举值,默认上方; 2、可以自定义位置传入IPosition,注意IPosition中的top和left跟平台的top,left是一致(没有乘以设备像素比ratio),需要开发者自己调试位置
         * @param scale 默认为跟屏幕一样的宽度,可以通过设置缩放比例来调整大小。当然,平台有规定最大或最小宽度,函数内部会自动计算。
         */
        public loadBanner(adUid: string, location: EAdBannerLocation | IPosition = EAdBannerLocation.TOP, scale: number = 1.0) {
            this._banner?.destroy();
            let size: ISize = getSysWinSize();
            // 当 style.width 小于 300 时,会取作 300。 当 style.width 大于屏幕宽度时,会取作屏幕宽度。
            let width = size.width * scale;
            width = width < 300 ? 300 : width; // 最小值矫正
            width = width > size.width ? size.width : width; //最大值矫正
            this._banner = typeof location === 'number' ? new ADBanner(adUid, location === EAdBannerLocation.TOP, width, false) : new ADBanner(adUid, location, width, false);
        }

        /**
         * 显示横幅广告
         */
        public showBanner() {
            if (this._banner) {
                this._banner.show();
            } else {
                console.warn('MiniGameSDK: banner is null, you must call loadBanner(...) first!');
            }
        }

        /**
         * 隐藏横幅广告
         */
        public hideBanner() {
            this._banner?.hide();
        }

        /**
         * 弹出插屏广告
         * @param adUid 广告单元id
         */
        public showInterstitial(adUid: string) {
            if (this._interstitial && this._interstitial.aduid === adUid) {
                this._interstitial.show();
            } else {
                this._interstitial?.destory();
                this._interstitial = new ADInterstitial(adUid);
                this._interstitial.show();
            }
        }

        /**
         * 加载原生模板广告,不会显示。只有你在调用showCustom时才会显示。
         * 由于原生模板广告在微信服务后端可以定制宽度大小,个数,缩放比例等,所以位置调整要根据设置的宽度来定。抖音不支持本函数,会调用无效!
         * @param adUid 广告ID
         * @param location 位置有两种情况:1、可以传入枚举值,默认上方; 2、可以自定义位置传入IPosition,注意IPosition中的top和left跟平台的top,left是一致(没有乘以设备像素比ratio),需要开发者自己调试位置
         * @param scale 缩放比例,默认是1,即不缩放。这个缩放并不是自己填,而是根据微信MP后台你配置的原生模板广告的缩放比例填,目前有100%,90%,80%三种,一般情况不用修改。若有后台修改,记得传入值,例如90%就传入0.9。
         */
        public loadCustom(adUid: string, location: IPosition = { top: 0, left: 0 }, scale: number = 1) {
            // this._custom?.destroy();
            // this._custom = new ADCustom(adUid, location.top, location.left, scale);
            if (this._customs[adUid]) {
                console.log(`${adUid} has been loaded.`);
                return;
            }

            this._customs[adUid] = new ADCustom(adUid, location.top, location.left, scale);
        }

        /**
         * 显示自定义广告。
         * @param adUid 广告的唯一标识符。使用此标识符来查找和显示特定的自定义广告。
         * 
         * 此方法尝试根据提供的adUid显示一个自定义广告。如果给定的adUid对应的自定义广告已加载,
         * 则调用该广告的显示方法。如果广告未加载,则在控制台输出警告信息。
         */
        public showCustom(adUid: string) {
            if (this._customs[adUid]) {
                this._customs[adUid].show();
            } else {
                console.warn(`You have not load ${adUid} of Custom AD, can not show!`);
            }
        }

        /**
         * 隐藏指定的自定义广告单元
         * 
         * 此方法用于隐藏通过广告单元标识符(adUid)指定的自定义广告。如果指定的广告单元已加载并显示,
         * 则将其隐藏;如果广告单元未加载,则在控制台输出警告信息。
         * 
         * @param adUid 广告单元标识符,用于唯一标识一个自定义广告单元。
         */
        public hideCustom(adUid: string) {
            if (this._customs[adUid]) {
                this._customs[adUid].hide();
            } else {
                console.warn(`You have not load ${adUid} of Custom AD, can not hide!`);
            }
        }

        /**
         * 由于微信和抖音视频广告机制不同,微信可以看的视频广告个数只有0和1个,抖音平台则可以看0~maxVideoCount
         * @param adUid 广告ID。如果与上一次UID不同,则内部会重新创建实例。开发者完全不用关心这个细节。
         * @param onVideoResult 两个参数:第一个res是EAdVideoResult定义,第二count是用户看了多少个视频广告。 
         * @param target onVideoResult的拥有者
         * @param maxVideoCount 最大视频个数。默认是3,仅对抖音平台生效。微信平台看完视频count的结果永远是1或0
         */
        public showVideo(adUid: string, onVideoResult: (res: EAdVideoResult, count: number) => void, target?: any, maxVideoCount: number = 3) {
            
             
            

            if (this._video && this._video.aduid === adUid) {
                console.info('show','进来了');
                this._video.show(onVideoResult, target, maxVideoCount);
            } else {
                this._video?.destory();
                this._video = new ADVideo(adUid);
                this._video.show(onVideoResult, target, maxVideoCount);
            }
        }

        /**
         * 销毁内部所有实例,清空内存
         */
        public destroyAll() {
            this._banner?.destroy();
            this._banner = null;

            this._interstitial?.destory();
            this._interstitial = null;

            this._video?.destory();
            this._video = null;

            if (this._customs) {
                for (let val in this._customs) {
                    this._customs[val]?.destroy();
                }
                this._customs = {};
            }
        }
    }

    export enum EGameClubIcon {
        /** 绿色图标 */
        GREEN = 'green',

        /** 红色图标 */
        WHITE = 'white',

        /** 有黑色圆角背景的白色图标 */
        DARK = 'dark',

        /** 有白色圆角背景的绿色图标 */
        LIGHT = 'light'
    }

    export class GameClub {
        private static _instance: GameClub;

        static get instance(): GameClub {
            if (!this._instance) {
                this._instance = new GameClub();
            }
            return this._instance;
        }

        private _club: any;

        private constructor() {

        }

        /**
         * 创建游戏圈按钮
         * @param icon 
         * @param position 
         * @param size 
         * @param openLink 
         */
        create(icon: EGameClubIcon = EGameClubIcon.GREEN, position: IPosition = { top: 0, left: 0 }, size: ISize = { width: 40, height: 40 }, openLink?: string) {
            if (isWechat()) {
                // @ts-ignore
                this._club = wx.createGameClubButton({
                    icon: icon,
                    style: {
                        left: position.left,
                        top: position.top,
                        width: size.width,
                        height: size.height
                    },
                    openlink: openLink
                });
            }
        }

        show() {
            this._club?.show();
        }

        hide() {
            this._club?.hide();
        }

        destory() {
            this._club?.destroy();
        }
    }


    /**
     * 振动类型
     */
    export enum EVirbrateType {
        /**
         * 短振动
         */
        SHORT,

        /**
         * 长振动
         */
        LONG
    }

    /**
     * 平台常用API合集
     */
    export class API {
        private static _loginCode: string = null;
        private static _loginAnonymousCode: string = null;
        private static _hasInitWechatCloudFunction: boolean = false;


        /**
         * 分享app给朋友,微信小游戏分享是没有onSuccess回调的。
         * @param title 标题
         * @param description 细节描述信息 
         * @param imageUrl 图片地址
         * @param query 查询信息
         * @param onSuccess 抖音会回调,微信不会回调
         */
        static shareAppToFriends(title: string, description: string = '', imageUrl?: string, query?: string, onSuccess?: () => void) {
            if (isWechat()) {
                try {
                    //@ts-ignore
                    wx.shareAppMessage({
                        title: title,
                        imageUrl: imageUrl,
                        query: query,
                    });
                } catch (err) {
                    console.log(`share faild: ${err}`);
                }
            }

            if (isBytedance()) {
                //@ts-ignore
                console.info('字节分享方法');
                tt.shareAppMessage({
                    title: title,
                    desc: description,
                    imageUrl: imageUrl ?? '',
                    query: query ?? '',
                    success(res: any) {
                        console.log('share success:', res);
                        onSuccess?.();
                    },
                    fail(res: any) {
                        console.log('share fail:', res);
                    }
                });
            }
        }

        /**
         * 显示提示信息
         * @param title 标题
         * @param duration 时长(单位:秒)
         * @returns 
         */
        static showToast(title: string, duration: number = 2) {
            if (isWechat()) {
                // @ts-ignore
                wx.showToast({
                    title: title,
                    icon: 'success',
                    duration: duration * 1000
                });
            }

            if (isBytedance()) {
                //@ts-ignore
                tt.showToast({
                    title: title,
                    duration: duration * 1000,
                    success(res: any) {
                        console.log(`${res}`);
                    },
                    fail(res: any) {
                        console.log(`showToast调用失败`);
                    },
                });
            }
        }

        /**
         * 设备震动效果,默认为短震动。注意:可能一些机型不会生效,具体看平台方的说明
         * @param type MiniGameSdk.API.EVirbrateType
         */
        static vibrate(type: EVirbrateType = EVirbrateType.SHORT) {
            if (isWechat()) {
                switch (type) {
                    case EVirbrateType.SHORT:
                        //@ts-ignore
                        wx.vibrateShort({
                            success(res: any) {
                                console.log('vibrate success:', res);
                            },
                            fail(res: any) {
                                console.log('vibrateShort failed', res);
                            },
                        });
                        break;
                    case EVirbrateType.LONG:
                        //@ts-ignore
                        wx.vibrateLong({
                            success(res: any) {
                                console.log('vibrate success', res);
                            },
                            fail(res: any) {
                                console.log(`vibrateLong failed`, res);
                            },
                        });
                        break;
                    default:
                        break;
                }
            }

            if (isBytedance()) {
                switch (type) {
                    case EVirbrateType.SHORT:
                        //@ts-ignore
                        tt.vibrateShort({
                            success(res: any) {
                                console.log('vibrate success:', res);
                            },
                            fail(res: any) {
                                console.log('vibrateShort failed', res);
                            },
                        });
                        break;
                    case EVirbrateType.LONG:
                        //@ts-ignore
                        tt.vibrateLong({
                            success(res: any) {
                                console.log('vibrate success', res);
                            },
                            fail(res: any) {
                                console.log(`vibrateLong failed`, res);
                            },
                        });
                        break;
                    default:
                        break;
                }
            }
        }

        /**
         * 重启小游戏
         */
        static reboot() {
            if (isWechat()) {
                //@ts-ignore
                wx.restartMiniProgram({
                    success: () => {
                        console.log('restart success');
                    },

                    fail: () => {
                        console.log('restart failed');
                    }
                })
            }

            if (isBytedance()) {
                try {
                    // @ts-ignore
                    tt.restartMiniProgramSync();
                } catch (error) {
                    console.log(`restartMiniProgramSync`, error);
                }
            }
        }

        /**
         * 退出小游戏
         */
        static exit() {
            if (isWechat()) {
                //@ts-ignore
                wx.exitMiniProgram({
                    success: () => {
                        console.log('exit success');
                    },
                    fail: () => {
                        console.log('exit failed');
                    }
                });
            }

            if (isBytedance()) {
                // @ts-ignore
                tt.exitMiniProgram({
                    success(res: any) {
                        console.log("exit success:", res?.data);
                    },
                    fail(res: any) {
                        console.log("exit fail:", res?.errMsg);
                    },
                });
            }
        }

        /**
         * 显示转发按钮。通常在刚进入游戏的时候调用。
         * 主要是打开平台“...”这个按钮里面的分享菜单,一般默认是关闭的,需要调用这个函数打开。可以让用户分享你的游戏入口。
         */
        static showShareMenu() {
            if (isWechat()) {
                //@ts-ignore
                wx.showShareMenu({
                    withShareTicket: true,
                    menus: ['shareAppMessage', 'shareTimeline'],
                    success: () => { },
                    fail: () => { },
                    complete: () => { }
                });
            }

            if (isBytedance()) {
                //@ts-ignore
                tt.showShareMenu({
                    success(res: any) {
                        console.log("show menu is showing");
                    },
                    fail(err: any) {
                        console.log("showShareMenu:", err.errMsg);
                    },
                    complete(res: any) {
                        console.log("showShareMenu complete");
                    },
                });
            }
        }

        /**
         * 微信小游戏:跳转到另外一款小游戏
         * 抖音小游戏:跳转到指定的视频界面
         * @param targetId 微信小游戏appid或者视频界面
         */
        static navigateTo(targetId: string, onSuccess?: () => void) {
            if (isWechat()) {
                // @ts-ignore
                wx.navigateToMiniProgram({
                    appId: targetId,
                    extraData: {
                        foo: 'bar'
                    },
                    envVersion: 'develop',
                    success(res: any) {
                        onSuccess?.();
                    }
                });
            }

            if (isBytedance()) {
                // @ts-ignore
                tt.navigateToVideoView({
                    videoId: targetId,
                    success: (res: any) => {
                        onSuccess?.();
                    },
                    fail: (err: any) => {
                        console.log("bytedance navigateToVideoView fail", err);
                    },
                });
            }
        }


        /**
         * 小游戏平台登录功能。微信返回code,抖音返回code和anonymousCode。用于登录的凭证,需要把这个code传回你的服务器程序中去调用code2Session
         * @param callback (code, anonymousCode) 第一个参数为code,微信和抖音都支持;第二个参数为匿名设备ID,仅抖音支持,失败都返回null
         */
        static login(callback: (code: string, anonymousCode: string) => void) {
            let loginPlatform = () => {
                if (isWechat()) {
                    //@ts-ignore
                    wx.login({
                        success: (res: { code: any; errMsg: any; }) => {
                            if (res.code) {
                                API._loginCode = res.code;
                                API._loginAnonymousCode = null;
                                callback?.(API._loginCode, API._loginAnonymousCode);
                            } else {
                                console.log('login error:', res.errMsg)
                            }
                        },

                        fail: () => {
                            API._loginCode = null;
                            API._loginAnonymousCode = null;
                            callback?.(API._loginCode, API._loginAnonymousCode);
                            console.log('login fail')
                        }
                    });
                } else if (isBytedance()) {
                    //@ts-ignore
                    tt.login({
                        force: true,
                        success(res: any) {
                            console.log(`login ${res.code} ${res.anonymousCode}`);
                            if (res.code) {
                                API._loginCode = res.code?.toString();
                                API._loginAnonymousCode = res.anonymousCode?.toString();
                                callback?.(API._loginCode, API._loginAnonymousCode);
                            } else {
                                console.log('login error:', res.errMsg)
                            }
                        },
                        fail(res: any) {
                            API._loginCode = null;
                            API._loginAnonymousCode = null;
                            callback?.(API._loginCode, API._loginAnonymousCode);
                            console.log(`login fail`, res);
                        },
                    });
                } else {
                    API._loginCode = null;
                    API._loginAnonymousCode = null;
                    callback?.(API._loginCode, API._loginAnonymousCode);
                    console.log('not mini game platform, login codes are all null');
                }
            }



            if (!API._loginCode) {
                loginPlatform();
            } else {
                if (isWechat()) {
                    //@ts-ignore
                    wx.checkSession({
                        success() {
                            console.log(`session is valid, use current code:`, API._loginCode);
                            callback?.(API._loginCode, API._loginAnonymousCode);
                        },
                        fail() {
                            console.log(`session expired`);
                            loginPlatform();
                        }
                    });
                } else if (isBytedance()) {
                    //@ts-ignore
                    tt.checkSession({
                        success() {
                            console.log(`session is valid, user current code: ${API._loginCode}, ${API._loginAnonymousCode}`);
                            callback?.(API._loginCode, API._loginAnonymousCode);
                        },
                        fail() {
                            console.log(`session expired`);
                            loginPlatform();
                        },
                    });

                } else {
                    console.log('not mini game platform, login null');
                    callback?.(null, null);
                }
            }
        }

        /**
         * 调用微信云函数。由于参数需要自定义,所以为any,需要自行解释。函数只完成通道和处理一场的作用
         * @param callback 返回云函数调用结果。需要检查返回参数是否为空,失败的时候为空
         * @param name 云函数的名字
         * @param data 云函数的内容
         */
        static callWechatCloudFunction(callback: (res: any) => void, name: string, data: {}) {
            if (!isWechat()) {
                console.log('Not wechat platform, not support callWechatCloudFunction');
                return;
            }

            this.login((code: string, anonymousCode: string) => {
                if (!API._hasInitWechatCloudFunction) {
                    //@ts-ignore
                    wx.cloud.init();
                    API._hasInitWechatCloudFunction = true;
                }
                //@ts-ignore
                wx.cloud.callFunction({
                    name: name,
                    data: data,
                    success: (res: any) => callback?.(res),
                    fail: (err: any) => {
                        console.log('wechat cloud function error:', err);
                        callback?.(null);
                    }
                });
            });
        }

        /**
         * 存储用户信息,数据量不能大。可以考虑用于分数排行榜。用户之间可共享排行数据。
         * @param key 
         * @param value 
         */
        static setUserCloudStorage(key: string, value: string) {
            if (isWechat()) {
                // @ts-ignore
                wx.setUserCloudStorage({
                    KVDataList: [{ key: key, value: value }],
                    success: () => console.log(`set cloud storage success:${key}, value:${value}`),
                    fail: (err: any) => console.log('set cloud storage error:', err)
                });
            }

            if (isBytedance()) {
                // @ts-ignore
                tt.setUserCloudStorage({
                    KVDataList: [{ key: key, value: value, }],
                    success: () => console.log(`set cloud storage success:${key}, value:${value}`),
                    fail: (err: any) => console.log('set cloud storage error:', err)
                });
            }
        }
    }


    /**
     * 抖音侧边栏专属接口
     */
    export class BytedanceSidebar {
        /**
         * 本游戏在抖音环境下启动监控,需要放在全局环境中,保证能第一时间启动。因为可能监听抖音失败(抖音小游戏官方的说明)!
         * @param onResult 包含一个boolean参数的函数
         * @param target 上述函数的拥有者,如果是类的成员函数,需要传入this。普通或匿名函数忽略即可。
         */
        static listenFromSidebar(onResult: (success: boolean) => void, target?: any) {
            if (!isBytedance()) {
                onResult?.call(target, false);
                return;
            }
            // @ts-ignore
            tt.onShow((res: any) => {
                console.log('onShow launch res:', res);
                if (res.scene === '021036') {
                    onResult?.call(target, true);
                    console.log('launch from sidebar');
                } else {
                    onResult?.call(target, false);
                    console.log('NOT launch from douyin sidebar!');
                }
            });

            // @ts-ignore
            let options = tt.getLaunchOptionsSync();
            if (options && options.scene === '021036') {
                onResult?.call(target, true);
            }
        }

        /**
         * 检测抖音侧边栏是否存在
         * @param onResult 包含一个boolean参数的函数
         * @param target 上述函数的拥有者,如果是类的成员函数,需要传入this。普通或匿名函数忽略即可。
         * @returns 
         */
        static checkSideBar(onResult: (success: boolean) => void, target?: any) {
            if (!isBytedance()) {
                onResult?.call(target, false);
                return;
            }

            //@ts-ignore
            tt.checkScene({
                scene: "sidebar",
                success: (res: any) => {
                    console.log("check scene success: ", res.isExist);
                    onResult?.call(target, <boolean>res.isExist);

                },
                fail: (res: any) => {
                    console.log("check scene fail:", res);
                    onResult?.call(target, false);
                }
            });
        }

        /**
         * 跳转到抖音侧边栏
         * @param onResult 包含一个boolean参数的函数
         * @param target 上述函数的拥有者,如果是类的成员函数,需要传入this。普通或匿名函数忽略即可。
         * @returns 
         */
        static navigateToSidebar(onResult: (success: boolean) => void, target?: any) {
            if (!isBytedance()) {
                console.log("not douyin platform!");
                onResult?.call(target, false);
                return;
            }

            // @ts-ignore
            tt.navigateToScene({
                scene: "sidebar",
                success: () => {
                    console.log("navigate success");
                    onResult?.call(target, true);
                },
                fail: (res: any) => {
                    console.log("navigate failed reason:", res);
                    onResult?.call(target, false);
                },
            });
        }
    }

}

 

抖音小程序、微信小程序创建广告位 抖音小程序创建广告位 阅读详情

相关推荐

微信小程序广告功能

(1)责任:个体工商户在面临债务问题时,用个人财产抵债。企业是以注册资本为限承担债务问题,不牵连个人财产。(2)成本:个体工商户的注册成本仅需刻章、税务登记等小额费用大概在300~1000元。企业需认缴注册资本,加上代理记账等年成本大概要2000~5000元。(3)注销难度:个体工商户注销流程简单,大概一个月内完成。企业注销流程复杂,它需要清算公告,税务注销等耗时3~6个月。(4)广告权限:两者均可开通微信流量主,但是公司主体更易通过其他平台审核。

2401_87078403的博客 4205

微信小程序广告接入

前天看了看以前写的微信小程序,发现访问破了1000了,哈哈终于可以在自己写的小程序里面插入广告,现在记录一下怎么在小程序中插入广告吧: 第一步开通流量主 开通条件很简单就是总访问量过1000: 同意协议并点击下一步。 填写个人的相关信息,包括身份证、收款账户等等。 上面的开户名称 其实就是 开户姓名,最后提交,系统会进行审核,审核时间说是大约一周。 第二步在小程序接入广告 创建广告位 选择要接入广告类型 并在下方填入广告位名称 点击确认后,进入广告位列表: 点击获取代码,然后复制里面的代码

孤夜的博客 3万+

抖音跳转能力总结攻略

保留当前页面,跳转到应用内的某个页面,但是不能跳转到 tabBar 页面,使用 tt.navigateBack 可以返回到原页面。跳转到分享的视频播放页面。跳转到另一个小程序。redirectTo、navigateTo 等页面跳转的 api 只支持 url 为 / 开始的绝对路径。web-view 网页容器该组件是一个用于承载网页的容器,将 H5 切入到小程序内部,铺满整个页面。使用该组件要进行业务域名配置,仅支持添加开发者可控制(能放置校验文件到域名根目录)的域名。

五角大寨 5285

优快云下个东西怎么这么麻烦

z## 新的改变 cxcxc 1. 全新的界面设计 ,将会带来全新的写作体验; 2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示; 3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示; 4. 全新的 KaTeX数学公式 语法; 5. 增加了支持甘特图的mermaid语法1 功能; 6. 增加了 多屏幕编辑 Markdown文章...

dreamfufish的博客 275

从0开发小程序,一个月时间实现盈利!内附抖音去水印原理

一、开发前奏 1.背景 近几年短视频行业的兴起,涌现出抖音快手等优秀的app,但是在app上发现优秀视频想要下载到本地时,又奈何总是全程有水印又末尾有平台独白,搜索众多app和小程序大部分要嘛广告众多烦人,要嘛每天有解析次数限制,要嘛超过次数就要收费的。刚好本人是个码农,我想,那何不自己开发一个小程序解决自己需求的同时,又能够帮助他人呢(当初没想到竟然能盈利)。 2.选型 技术选型采用微信小程序做开发,一来是微信小程序发布后在android和ios都可以使用,二来是去水印只是个简单的小功能,没必要再开发一个

Smhhs 4307

短视频去水印微信小程序,免费去除视频水印

最近不知怎么的,偶然浏览到一个挺简单漂亮的视频解析小程序帖子,没过多久又偶然浏览到一个短视频去水印github项目,也是巧,于是就把两个项目结合了一下,然后发布了小程序。 也不知道怎么推广,索性写篇博客吧,目前支持 抖音、快手、微视、最右、皮皮虾等多个平台。 原本的小程序代码只有一个首页,我又自己加了个人中心页、记录列表页及登录鉴权相关的基础功能,第一个版本就这样上线了。 有机会的话我会再补一篇...

小白成神路 1万+

抖音小程序开发:从入门到入行实战指南

本文介绍了抖音小程序开发的核心要点。作者通过一个5.2万元的项目实践,分享了从环境搭建到核心技术实现的全过程。文章首先分析了抖音生态的7亿日活用户优势和小程序的四大特点:无需安装、社交裂变、低成本开发和丰富入口。随后详细讲解了开发准备、项目创建和配置文件解析,并重点剖析了页面生命周期、数据绑定、组件系统等关键技术。通过代码示例展示了如何实现页面跳转、API调用和事件处理等核心功能,为开发者提供了从零开始构建抖音小程序的完整指南。

百锦再的博客 1540

抖音短剧小程序软件制作支持版权方分成

总而言之,《微信短剧小程序上百案例,带支付收益模式,支持iaa广告付费模式》绝对值得每一位希望投身这一领域的朋友们认真考虑一番。当然啦,在正式启动之前还需要准备一些必要的证件材料比如《广播电视节目制作经营许可证》,不过好消息是有专门机构可以帮助代办这些手续哦~所以心动不如行动起来吧!

j17639996551的博客 800

消消乐抖音快手微信小程序看广告流量主开源

消消乐抖音快手微信小程序看广告流量主开源

云起SAAS 1305

紫色UI抖音趣味测评小程序源码部署与流量主接入实战

小程序开发已成为轻量级互动应用的主流形态,测评类小程序凭借即时反馈与社交裂变属性,在抖音生态中迅速崛起。其核心逻辑基于题库管理、计分引擎与结果页展示,通过紫色系UI设计强化品牌辨识度与分享传播力。从服务器环境搭建、数据库配置到前端编译上传,开发者需完成HTTPS域名备案、接口白名单等关键步骤;接入流量主时,合理布局激励视频、插屏与Banner广告位,并遵循平台合规要求控制频次。掌握测评引擎数据结构与后台管理配置,即可批量复制测评模板,实现多端分发与广告变现。本文以一套紫色UI源码为例,完整拆解测评小程序从开

weixin_30291791的博客 454

面试中常考的数学题——截木棍、圆上取点、赛马、红蓝墨水,测试毒药、坐到正确座位问题

文章目录1.将一根木棒截成三段,问能够组成三角形的概率;2.在圆上任取三点,问能够组成锐角、直角、钝角三角形的概率;3.共有25匹马,找出最快的3匹,只有5个赛道,每次比赛只能得到5匹马的速度排序,最少需要多少次比赛;4 有两瓶红蓝墨水,体积一样,现在从红墨水中舀一勺加入蓝墨水中,搅拌均匀后,在从蓝墨水中舀一勺加到红墨水中,试问这两瓶墨水哪瓶纯度更高。 1.将一根木棒截成三段,问能够组成三角形的概率; 来源:https://blog.youkuaiyun.com/weixin_41245919/article/deta

weixin_41558411的博客 4904

抖音壁纸小程序怎么做?手把手教你0元拥有自己的壁纸小程序

抖音壁纸小程序怎么做?手把手教你0元拥有自己的壁纸小程序

zhichina的博客 4053

Python3.8下MvCameraControl.dll加载失败?3种方法彻底解决FileNotFoundError

本文针对Python3.8及以上版本在Windows平台调用MvCameraControl.dll时出现的FileNotFoundError问题,深入剖析了其根源在于Python 3.8引入的DLL加载安全机制变更。文章提供了三种核心解决方案:显式指定DLL完整路径、使用os.add_dll_directory()添加可信目录,以及利用ctypes的winmode参数进行精细控制,并给出了工程化封装建议,帮助开发者彻底解决此兼容性问题。

weixin_29093017的博客 191

看广告进群抖音快手微信小程序看广告流量主开源

看广告进群抖音快手微信小程序看广告流量主开源

云起SAAS 942

让 AI 自己“画施工图”——基于扩散模型的智能 CAD 管线生成

AI驱动CAD管线设计革命:Layout2CAD实现30秒自动化出图 针对设计院70%时间耗费在管线绘制的问题,研究团队基于Stable Diffusion开发了Layout2CAD系统,实现建筑草图到DWG施工图的智能转换。该系统采用三阶段流程:语义分割建筑底图→扩散生成多通道Heatmap(含管径/标高信息)→矢量化输出DWG实体,结合129M参数的多模块模型(Diffusion UNet+GraphRefiner)及规范判别器,确保1mm精度并自动满足GB50015-2019标准。

qq_74383080的博客 2014

从ST电机库到TI InstaSPIN:手把手对比两种主流FOC实现中的坐标变换差异

本文深入对比了ST电机库与TI InstaSPIN在FOC实现中的坐标变换差异,包括坐标系定义、变换系数和角度处理等关键点。针对BLDC和PMSM电机控制,提供了从理论到实践的移植方案,帮助工程师快速解决平台切换中的性能问题。特别解析了Clarke/Park变换在两种实现中的微妙差异及其对PI控制的影响。

weixin_28724661的博客 398

抖音、头条小程序开发与营运攻略,猛戳获取

「头条、抖音小程序」是即微信、百度、支付宝后,上线最晚的小程序。但这两者亦是即微信之后,最具电商潜力的小程序。近来,头条与抖音小程序如何开发与营运正成品牌关切的热门话题。 本文多图预警,可依照下方目录快速查阅相关章节: 抖音头条小程序优势何在? 抖音头条小程序入口在哪儿? 抖音头条小程序VS微信小程序,体验如何? 抖音头条小程序,如何推广与冷启动? 抖音头条小程序,如何入驻与开发? *注:本文...

TMOHP的博客 1829

ROS2 -Jazzy 一步一步(第一步_工作空间以及编译)

文件夹作用特点是否需要手动创建/维护src存放自己写的 ROS 2 包一个 workspace 可以有多个包需要手动创建build保存编译过程中的中间文件每个包生成对应子目录自动生成,可删除install保存编译完成后的功能包每个包有独立子目录,含可执行文件自动生成,可删除log保存编译日志用于查看错误原因、调试自动生成,不需修改colcon是 ROS 2 推荐使用的构建工具自动处理功能包的依赖和编译顺序一条命令就能编译整个工作空间。

jerrykorea的博客 1380

抖音直播→微信小程序:私域引流全链路实操指南(合规避坑 + 高转化技巧)

要将抖音直播间流量高效引流至微信小程序并发展私域用户,需结合平台规则与技术工具构建合规链路。

hedian158的博客 5191

01 AUTOSAR CP标准文档阅读指南

01 AUTOSAR CP标准文档阅读指南

汽车软件工程师 | 好奇博主 | 处女座 1134

用UDP协议在dos命令行里模拟一个聊天程序

/* 需求: 在dos命令行里模拟一个聊天程序 有收数据的部分,和发数据的部分,这两部分需要同时执行。 那就需要用到多线程技术。 一个线程控制收,一个线程控制发。 */ import java.io.*; import java.net.*; class C

s_x_x的记录 1955

微信与抖音小程序功能、推广场景、用户体验和技术架构等方面全方位对比!

随着移动应用市场的快速发展,小程序作为一种轻量级的应用程序,以其简单易用、快捷方便的优势受到越来越多人的青睐。其中,微信小程序和抖音小程序是目前市场上最受欢迎的两款小程序。本文将从功能对比、推广场景、用户体验和技术架构等方面对微信小程序和抖音小程序进行详细的比较分析

u013234541的博客 2060

Day 01: 与Python的第一次亲密接触

环境搭建 、第一个程序 Hello, World!、以及Python之禅 (The Zen of Python) 的解读。

杨小扩的博客 220

抖音常见的十种变现方式

很多为了在抖音来赚米的人都有这样一个共识,就是“不能变现的抖音号都是‘失败’的”。我们做抖音的目的就是为了盈利,下面来看看有哪些常见的变现方式? 一、广告变现 广告是所有抖音达人最直接的一种变现方式,如果达人没有自己的店铺、产品或者品牌的话,接广告来变现是最合适的。目前,抖音已上线对接广告资源合作的星图平台,主要接广告的方式有广告公司派单、广告主主动找到达人、达人主动寻找广告主和签约MCN机构等。当用户的抖音号有一定数量的粉丝和稳定的播放量后,广告主就会主动找上门来,可以通过帮他们发软广、硬广的方式来变

Gamin 5万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

微信小程序 视频列表滑动无限循环(仿抖音)

微信小程序 视频列表滑动无限循环(仿抖音),安卓ios表现基本一致,非swiper组件实现,滑动效果流畅不卡顿,实现了列表无限循环。完整代码在下面。。。支持位置导航、拨打电话、复制微信号、分享、联系客服和拖动视频进度功能,暂未添加评论留言功能,后期会逐步增加。

老虎帅呆了的博客 7238

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

三消消乐益智小游戏抖音快手微信小程序看广告流量主开源

三消消乐益智小游戏抖音快手微信小程序看广告流量主开源

云起SAAS 1850

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: python数据分析与可视化介绍
下一篇: python写的window小工具-一键设置ip自动获取ip
互联网时光机
博客等级 码龄20年 400粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网时光机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值