分类: 技术

  • WordPress数据库修改表前缀完整版教程

    WordPress数据库修改表前缀完整版教程

    mysql的表前缀

    mysql的表前缀在大部分的程序都会有,这个前缀是为了区分程序,如果你在某个数据库中,放入了多个程序的数据,那么有了表前缀,你就可以非常清晰地区分他们,多程序在数据库中也不会因为没有前缀而导致冲突。

    比如大部分程序都有 options表,这个表代表我们的一些设置,如WordPress的前缀默认为wp_ 那么在数据库中,wp_options则代表这个表数据为WordPress的。

    一般情况下,什么情况下需要修改WordPress的表前缀呢?

    一般来说,如果我们需要在一个数据库中,安装多个WordPress网站,那么我们就需要放入多个不同前缀的数据到数据库中。

    这种情况下一般是虚拟主机,因为虚拟主机的数据库是不允许你新建多个数据库的,因此你需要在一个数据库中放入多个WordPress的数据表。

    比如站点1 为默认的wp_  站点2 为 wp2_

    修改表前缀一般有2种情况(都是在无法新建数据库的情况下)

    • 第一:我建立好了一个WordPress网站,现在想要复制整个网站的内容,到另一个网站去,两个网站的数据一致,我比较方便修改,而不需要重新在后台传。
    • 第二:主题提供了导入数据,我需要在一个数据库中导入2个网站,但提供的导入数据表前缀一致,那么我在导入一次之后,需要改变表前缀,再倒入另一个。

    ps.若你可以新建数据库,则完全无需修改表前缀,无需将多个网站安装进入同一个数据库中,建立不同的数据库安装不同的程序数据,方便管理。

    首先你需要一个数据库管理工具,最好是一台闲置的服务器,或者本地环境下的数据库,

    我们以phpmyadmin为例子:我们需要将wop_ 前缀修改为 wopen_

    本地环境phpmyadmin,首先导入我们所需要的数据库:

    WordPress数据库修改表前缀完整版教程

    导入完成止之后进入表结构,全选所有的表:

    WordPress数据库修改表前缀完整版教程

    拖动到最底部的选中项操作,选择修改表前缀:

    WordPress数据库修改表前缀完整版教程

    在弹出的界面中,输入需要替换的前缀和替换后的前缀,这里是wop_ 修改为wopen_:

    WordPress数据库修改表前缀完整版教程

    点击继续,就可以替换完成所有的前缀了,到了这一步,如果你将数据库导入到运营中的服务器登录,后台界面会显示“无权限访问这个界面”

    这是因为我们的用户数据权限前缀在此是无法修改到的,WordPress无法识别当前用户的级别造成的

    因此我们需要修改两个数据:

    1.options表中的user_roles字段

    打开options表,搜索user_roles(注意选择 %like%)

    WordPress数据库修改表前缀完整版教程

    搜索结果:

    WordPress数据库修改表前缀完整版教程

    将此数据修改一下,为wopen_user_roles

    WordPress数据库修改表前缀完整版教程

    保存即可

    2.修改user_meta中的数据,usermeta中的数据需要sql批量替换,因为数据要改的地方很多,一条一条的改不现实,所以提供一条sql命令进行修改:

    命令如下

    update `wopen_usermeta` set `meta_key`= replace(`meta_key`,'wop_','wopen_')  WHERE `meta_key` like "%wop_%";

    请特别注意,这里是示例的 wop_ 更改为wopen_

    在实际操作中,你需要根据你自己的更改需求去吧这个sql命令更换一下,上面的命令我用颜色进行了区分,很容易识别。

    这里执行修改完成之后, 再导出数据,导入你运营的数据库中就可以将完整的数据迁移过去了,登陆后台一些都会正常。

    以上为完整具体的手把手教你如何修改表前缀教程,若需要修改参考此教程即可完整的修改。

  • Google Play应用拒审+账号被封!你的自查做对了吗?

    前言

    本文基于Google Play官方政策与实战经验,系统梳理公司账号申请、应用上架的全流程细节,分享开发者常见的“踩坑点”,并提供可落地的方案解答。

    不用期望Google审核能给到具体封号的原因:

    “开发者有责任处理所有政策问题,并进一步核查,以确保应用或账号的其余部分完全符合政策规定。如果您未能解决您的账号和所有应用中违反政策的行为,我们可能会采取其他违规处置措施。

    如果您屡次或严重违反(例如应用含有恶意软件、存在欺诈行为以及可能危害到用户或设备)这些政策或 开发者分发协议(DDA),您的开发者帐号或相关的 Google Play 开发者帐号可能会被终止”。

    注意屡次违规(一般大于等于3次),真的会封号了。

    复盘拒审、封号原因,道路且长,更多的是需要每一位开发者自查纠正,积累经验。

    一、Google Play违规处置流程和处置措施

    以下内容来自于Google Play 政策中心

    1. Google Play违规处置流程

    在审核内容或账号是否违法或违反我们的政策时,我们会在做最终判定前考虑各种信息,包括应用元数据(例如应用名称、说明)、应用内体验、账号信息(例如过往的违规记录)、应用内的任何第三方代码、通过报告机制(如果适用)提供的其他信息,以及自发审核信息。

    请注意,您有责任确保您的应用内使用的第三方代码(例如某个 SDK)以及该第三方针对您的应用采取的做法均符合所有 Google Play 开发者计划政策。

    重点:应用元数据、应用内体验、账号信息、应用内的任何第三方代码、SDK。

    2. Google Play违规处置措施

    不同的违规处置措施会对您的应用产生不同的影响。我们结合使用人工与自动化评估机制来审核应用及应用内容,检测和评估哪些内容违反政策并会对用户和整个 Google Play 生态系统造成伤害。

    使用自动化模型有助于我们检测更多违规行为和更快地评估潜在问题,从而确保 Google Play 为所有人打造安全的使用体验。自动化模型会移除违反政策的内容,但如果需要更缜密的审查(例如需要了解内容的上下文)才能判定,模型会为内容添加标记,交由负责内容评估并且经过培训的操作人员和分析人员评估。然后,我们会利用人工审核的结果来构建训练数据,以进一步改进机器学习模型。

    重点:人工审核、机器审核、上下文信息、模型训练。

    PS:你的每一次违规,都在帮助Google Play训练模型!!!

    我们需要熟悉每一个风险环节,在排查原因之前,需要明确了解当前应用、账号属于哪一个违规处罚:

    2.1 被拒

    注意:在解决所有违反政策的行为之前,请勿尝试重新提交被拒的应用。

    2.2 下架

    注意:在解决所有违反政策的行为之前,请勿尝试重新发布已下架的应用。

    2.3 暂停

    注意:应用被暂停视同于受到警示,会对您的 Google Play 开发者账号的信誉造成不利影响。多次收到警示可能会导致个人以及相关的 Google Play 开发者账号被终止。

    2.4 公开范围受限

    注意:应用在 Google Play 上的曝光度受到限制,但可以正常访问链接。

    2.5 地区限制

    注意:特定地区的用户才能通过 Google Play 下载您的应用。

    2.6 账号受限状态

    注意:解决所有违反政策的行为后,将能重新发布应用。

    2.7 终止账号

    注意:如果您尝试开设一个新帐号,那么该新帐号也会被终止(不退还开发者注册费),因此请勿在您的任意帐号被终止时注册新的 Play 管理中心帐号。

    2.8 休眠账号

    注意:休眠账号是指处于闲置或弃用状态的开发者账号,可申诉退款或激活,也可以重新创建新账号。

    二、Google Play高危违规处置措施应对:拒审/封号

    Google Play提交应用被拒审的常见原因通常与违反其开发者政策有关。以下是一些常见的拒审/封号原因及其解决方法:

    1. 高风险行为

    原因:

    新开发者账号权重太低,新号提新包极大概率高风险行为封号。

    解决方法:

    • 通过科学养号措施活跃账号,提升账号权重。
    • 靠谱渠道购买老开发者账号。

    常见邮件:

    2. 违反隐私政策

    原因:

    应用未提供清晰、完整的隐私政策,或未正确处理用户数据。

    解决方法:

    • 在应用内和 Play Store 列表中添加隐私政策链接。
    • 确保隐私政策明确说明数据收集、使用和共享方式。
    • 遵守 GDPR、CCPA 等数据保护法规。

    常见邮件:

    3. 不当内容

    原因:

    应用包含色情、暴力、仇恨言论、歧视性内容等。

    解决方法:

    • 移除所有违规内容,包括文字、图像、音频和视频。
    • 确保应用内容适合所有年龄段的用户。

    常见邮件:

    4. 知识产权侵权

    原因:

    应用使用未经授权的受版权保护的内容(如图片、音乐、视频等)。

    解决方法:

    • 确保所有内容均为原创或已获得授权。
    • 移除未经授权的内容。

    5. 功能问题

    原因:

    应用存在崩溃、加载失败、功能无法使用等技术问题。

    解决方法:

    • 在提交前进行全面测试,修复所有已知问题。
    • 使用 Google Play 的 预发布测试工具 检查问题。

    6. 元数据违规

    原因:

    应用的标题、描述、截图或图标包含误导性信息、关键词堆砌或不相关内容。

    解决方法:

    • 确保元数据准确描述应用功能。
    • 避免使用无关的关键词或夸大宣传。

    7. 广告违规

    原因:

    广告展示方式不当(如遮挡内容、强制点击等),或包含违规内容。

    解决方法:

    • 遵循 Google 的广告政策,确保广告展示方式合理。
    • 使用合规的广告网络和内容。

    常见邮件:

    8. 应用评级不准确

    原因:

    应用内容与所选年龄评级不符。

    解决方法:

    • 根据应用内容选择合适的年龄评级。
    • 确保应用内容与评级一致。

    9. 恶意行为

    原因:

    应用包含恶意软件、间谍软件或欺诈行为。

    解决方法:

    • 移除所有恶意代码或行为。
    • 确保应用安全,不损害用户设备或数据。

    10. 重复应用

    原因:

    应用与现有应用功能高度相似,缺乏独特性。

    解决方法:

    • 确保应用具有独特的功能或内容。
    • 避免提交多个功能相似的应用。

    11. 支付政策违规

    原因:

    应用内购买未使用 Google Play 结算系统,或未正确处理订阅。

    解决方法:

    • 使用 Google Play 结算系统处理所有应用内购买。
    • 确保订阅管理符合 Google 的政策。

    12. 用户生成内容(UGC)管理不当

    原因:

    应用允许用户生成内容,但未提供有效的审核机制。

    解决方法:

    • 添加内容审核机制,过滤不当内容。
    • 提供举报功能,方便用户举报违规内容。

    13. 权限滥用

    原因:

    应用请求不必要的权限,或未合理使用权限。

    解决方法:

    • 仅请求与应用功能相关的权限。
    • 在隐私政策中说明权限用途。

    14. 目标 API 级别过低

    原因:

    应用未更新至最新的目标 API 级别。

    解决方法:

    • 将应用的目标 API 级别更新至 Google 要求的最低版本。

    15. 误导性行为

    原因:

    应用功能与描述不符,或诱导用户进行某些操作。

    解决方法:

    • 确保应用功能与描述一致。
    • 避免使用误导性设计或诱导用户行为。

    常见邮件:

    16. 违反家庭政策

    原因:

    针对儿童的应用未遵守 Google Play 家庭政策。

    解决方法:

    • 确保应用内容适合儿童。
    • 遵守广告和隐私政策的相关规定。

    本期结语

    Google Play应用违规,更多的是需要开发者自查,在排除可疑点以后,总结经验,避免下次出现相同问题,没有一个被封账号是无辜的,我们只能在自查完成以后积极申诉,主动承认错误。

    最后提醒:

    请仔细阅读每一条谷歌政策,定期关注政策更新。

    愿每一位开发者都能在Google Play的舞台上,以专业与匠心,收获更多。

    作者:Android出海
    来源:稀土掘金

  • 苹果开发者关联封号扫盲贴

    什么是关联封号
    开发者账号因为种种原因被封后,苹果官方为了防止开发者再次“作恶”,通过技术手段识别开发者是否通过重新开设账号继续上架产品,一旦识别到和原先封号的账号有关联,就会再次将新开设的账号查封,这个机制一般我们就叫关联封号。

    苹果通过什么方式判断账号是关联的
    关联手段有很多,包括但不限于:

    申请、登陆账号或测试所用的硬件设备(手机、电脑、笔记本)
    网络环境(IP段等)
    重新请求上架app的特征(代码,文件,请求域名)
    苹果账号(登陆了老账号)
    会员付费的信用卡
    开发者收款的银行卡
    app转移
    是不是一旦关联上,就一定会封号
    不一定。有一些不明显的关联,让苹果无法“确信”开发者是同一个人,可能一时半会儿不会被关联,但是风险一直存在,切勿冒险。

    如何防止苹果关联到原来的网络环境
    方法有很多,购买移动网卡,或手机热点等方式都是可以的,或者去公共的网络环境(咖啡厅等)。

    如果银行卡还是本人的,但是换一张卡可以吗
    虽然换了卡,但是银行卡还是本人的话,依然存在关联风险。最好是换个个体,比如亲人的。

    代码混淆可以规避代码关联吗
    可以,但不稳定。因为苹果的混淆识别一直在进步。

    如果知道我一个账号可能被关联了,但是我不更新它,账号会被封吗
    有可能不会。因为苹果关联的触发时机一般是在开发者提交应用审核的时候,所以如果开发者不提交应用审核,大部分时候苹果不会主动去审查关联和封号。

    我可以通过买二手手机和笔记本作为新申请的开发测试设备吗
    可以。风险较低,当然了,存在一个可能性就是买的二手设备已经被关联,但是一般这种情况概率较低,除非你找开发者买设备。

    通过号商买账号可靠吗
    任何号商卖的账号都存在风险,不管这个号商宣称自己有多安全。但是如果别无选择,也可以一试。

    如果被关联封号了,开新号上新产品有什么建议吗
    最重要的建议就是不要作死,以下注意事项可以作为参考。

    把新号当做一个全新的账号来养,杜绝和老号的关联。
    新产品的网络请求域名最好改换。
    新号登陆及关联的设备必须是全新的。
    新号登陆及相关网络环境也应该是全新的,最简单的做法是买一个移动网卡当专用环境。
    新号保持不乱更新的习惯,不然容易压低权重。

  • 如何禁用WordPress的自动更新功能?

    如何禁用WordPress的自动更新功能?

    WordPress自动更新版本功能如何关闭?

    WordPress的自动更新功能虽然能够确保网站安全,并保持最新状态,但在某些情况下,用户可能希望关闭这一功能,以下是关闭WordPress自动更新版本的详细步骤:

    方法一:通过代码禁用自动更新

    1、禁用所有自动更新:

    打开根目录下的wp-config.php文件。

    在文件中添加以下代码行:

    /** 关闭WordPress自动更新升级 */
    define(‘AUTOMATIC_UPDATER_DISABLED’, true);

    保存并关闭文件。

    2、仅禁用插件或主题的自动更新:

    如果你只想禁用插件或主题的自动更新,可以在当前主题的functions.php文件中添加以下代码:

    “`php

    add_filter( ‘auto_update_plugin’, ‘__return_false’ ); // 禁用插件自动更新

    add_filter( ‘auto_update_theme’, ‘__return_false’ ); // 禁用主题自动更新

    “`

    这些代码会分别禁止插件和主题的自动更新。

    3、禁用定时检查更新:

    要完全停止WordPress后台定时检查更新,可以添加以下代码到functions.php文件中:

    “`php

    remove_action(‘init’, ‘wp_schedule_update_checks’);

    wp_clear_scheduled_hook(‘wp_version_check’);

    wp_clear_scheduled_hook(‘wp_update_plugins’);

    wp_clear_scheduled_hook(‘wp_update_themes’);

    “`

    这将移除所有与自动更新相关的定时作业。

    方法二:使用Easy Updates Manager插件

    1、安装插件:

    访问WordPress后台,导航至“插件”>“添加新插件”。

    搜索“Easy Updates Manager”,找到插件后点击“安装”并激活。

    2、配置插件:

    激活插件后,导航至“设置”>“Updates Options”。

    在此处,你可以统一设置禁用所有更新,或者针对WordPress核心、插件、主题等单独设置自动更新、手动更新或禁止更新。

    3、查看更新日志:

    Easy Updates Manager还提供了更新日志选项,你可以看到具体的版本升级记录和日期,如果因为某个更新导致问题,可以及时回滚到上一个版本。

    相关问题与解答

    1、为什么需要关闭WordPress的自动更新功能?

    避免网站崩溃:自动更新可能会因为插件、主题与核心代码之间的不兼容性导致网站崩溃,尤其是在进行重大更新时,这种风险更高。

    控制更新实施方式:手动更新允许你控制更新的实施方式,并在出现问题时立即解决,这对于维护复杂的网站尤其重要。

    不必要的功能更改:自动更新可能会带来不需要的功能,干扰工作流程,调整每个元素和功能以适应独特的视觉可能需要大量工作量。

    2、关闭自动更新后如何手动更新WordPress?

    手动更新核心:登录到WordPress管理仪表盘,导航至“更新”,如果有可用的新版本,可以手动点击“更新现在”按钮来执行更新。

    手动更新插件和主题:同样在“更新”页面,选择需要更新的插件或主题,然后点击“更新”按钮,建议在更新前备份站点,以防万一。

    通过以上方法,你可以有效地关闭WordPress的自动更新功能,并根据需要手动进行更新,以确保网站的稳定和安全。

    各位小伙伴们,我刚刚为大家分享了有关“WordPress自动更新版本功能如何关闭?”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!

  • Uniapp打包成apk之后运行到ipad平板上无法横屏竖屏

    使用自定义基座可以自动通过重力感应横屏竖屏,但是打成APK之后就不生效…

    已解决了,manifest文件里加上,我感觉这个应该作为默认配置才好,而不应该额外开发,毕竟自动旋转是个基础功能.

    "app-plus" : {  
        "screenOrientation" : [  
             "portrait-primary",  
             "portrait-secondary",  
             "landscape-primary",  
             "landscape-secondary"  
        ],  
    }

    pagesjson文件里加上下列代码:

    "globalStyle": {  
            "pageOrientation": "auto"  
        },  
        "app-plus": {  
            "screenOrientation": [  
                "portrait-primary",     //可选,字符串类型,支持竖屏  
                "portrait-secondary",   //可选,字符串类型,支持反向竖屏  
                "landscape-primary",    //可选,字符串类型,支持横屏  
                "landscape-secondary"   //可选,字符串类型,支持反向横屏  
            ]  
        },
  • iOS IPA上传到App Store Connect的三种方案详解

    iOS IPA上传到App Store Connect的三种方案详解

    引言
    在iOS应用开发中,完成开发后的重要一步就是将IPA文件上传到App Store Connect以便进行测试或发布到App Store。无论是使用Xcode进行原生开发,还是通过uni-app、Flutter等跨平台工具生成的IPA文件,上传到App Store的流程都是类似的。苹果官方提供了三种上传IPA的方案,分别适用于不同的开发场景,帮助开发者在不同的环境中灵活高效地完成应用上传。

    本篇博客将详细介绍这三种方案,帮助开发者选择最适合自己的上传方式。

    方案一:通过Xcode上传IPA
    适用场景
    Xcode是iOS开发者的主要工具,也是开发者完成应用构建和上传的常用方式。它非常适合直接在开发环境中将应用上传到App Store Connect,尤其是对独立开发者或小团队而言,这是一种简单且高效的选择。

    具体步骤
    1.登录Apple开发者账号
    首选,确保你已经在Xcode中登录了你的Apple开发者账号。

    打开Xcode后,点击左上角菜单栏中的 “ Xcode -> Settings ” ,进入 “ Accounts ” 选项卡。
    在这里,你可以添加并登录你的Apple ID。如果已经登录,可以直接查看关联的开发者账号信息。

    2.选择正确的项目和目标
    确保你打开了你需要构建和上传的项目,并且已经选择了正确的Target(应用目标)。Target是项目的一个配置文件,定义了构建和发布应用的所有信息。

    3.构建并归档(Archive)项目
    首先选择构建目标设备为Any iOS Device (arm64)
    在Xcode菜单栏中,点击“Product -> Archive”以对项目进行归档。这个过程会生成一个可以上传的IPA包。
    构建成功之后,Xcode将会自动打开“Organizer”菜单下的“Achives”窗口,显示所有归档项目的列表。

    4.上传到App Store Connect
    在“Archives”窗口中,选择我们刚刚生成的归档文件,点击右侧的“Distribute App”按钮。
    选择“App Store Connect”作为分发目标,点击“Distribute”。接着选择“Upload”,因为我们是自动管理证书和签名,所以只需要确保账号对应。如果是手动配置证书选择合适的证书。
    Xcode将进行一系列的自动验证(如证书、描述文件等),并在一切正常的情况下开始上传IPA文件。

    5.等待上传完成
    上传过程中,Xcode会显示上传进度。上传成功后,你可以在App Store Connect中查看到应用。
    在App Store Connect的“TestFlight”或“分发”选项卡中,我们可以对应用进行测试或提交审核。
    优缺点
    优点:Xcode的方式最为直接,省去了复杂的配置步骤,适合各个阶段和规模的团队和以及不需要自动化流程的开发团队。
    缺点:仅适用于macOS环境,依赖Xcode工具,不能上传现有IPA,并且对CI/CD支持较弱。
    方案二:通过命令行工具(altool)上传IPA
    适用场景
    对于需要自动化部署或在CI/CD流水线中集成的开发团队来说,使用命令行工具上传IPA时一个高效的选择。通过altool,我们可以直接就爱那个IPA上传到App Store Connect,而无需依赖Xcode的图形页面。这个方案特别适合那些使用CI/CD工具链(如Jenkins、Fastlane等)来自动化上传和发布流程的开发者。

    具体步骤
    1.确保安装Xcode命令工具
    在使用altool之前,确保你的系统已经安装了Xcode的命令行工具。如果没有,可以通过以下命令进行安装:

    xcode-select –install
    2.生成App专用密码
    由于altool上传IPA需要认证,所以我们需要生成一个应用专用密码。操作步骤如下:

    登录Apple ID管理页面。
    进入“安全”部分,点击“生成App专用密码”。
    创建一个新的专用密码并将其保持。稍后在命令中使用。
    3.上传IPA文件
    使用altool命令上传IPA。具体命令如下:

    xcrun altool –upload-app -f “YourApp.ipa” -t ios -u “your@appleid.com” -p “app-specific-password”
    替换“YourApp.ipa”为你需要上传的IPA文件的路径。
    “your@appleid.com”是你的Apple开发者账号的邮箱地址。
    “app-specific-password”是你在上一步生成的应用专用密码。
    4.查看上传结果
    上传过程中,终端会显示上传的进度信息。上传完成后,命令行会给出成功或失败的反馈。如果成功你可以在App Store Connect中查看上传的IPA文件状态。如果上传失败,终端将输出相关的错误信息,便于排查问题。

    5.自动化集成
    你可以将altool命令与其他脚本或CI/CD工具结合,完成整个上传流程的自动化。例如,可以在Jenkins或Fastlane中通过脚本执行上传命令,实现CI流程中的无缝集成。

    常见问题与解决方案
    无效的App专用密码:如果出现密码错误,确保你使用的是为Apple ID生成的App专用密码,而不是普通额Apple ID密码。
    上传失败或中断:检查网络连接,并确保你使用的是最新版本的Xcode和命令行工具。如果问题依然存在,尝试重新生成归档或证书。
    优缺点
    优点:命令行工具非常适合自动化部署,能与CI/CD流程紧密集成,特别适合团队合作和频繁发布。
    缺点:需要一定的命令行操作经验,学习成本较高,且出错时排查难度相对较大。
    方案三:通过Transporter上传IPA
    适用场景
    Transporter是一款由Apple提供的独立上传工具,专门用于上传应用的二进制文件到App Store Connect。它适用于哪些不想使用Xcode,或者需要批量上传多个IPA的开发者。对于跨平台开发者(如uini-app、Flutter开发者),这个工具也非常实用,因为它独立于Xcode运行。之前使用Xcode上传效率慢,或者在App Store Connect迟迟看不见构建版本时,通常也会采用这个方案进行上传。

    具体步骤
    1.下载并安装Transporter
    打开Mac App Store,搜索“Transporter”并下载安装。
    安装完成后,启动Transporter应用。
    2.登录Apple开发者账号
    在Transporter应用页面中,点击“Sign In”按钮,使用你的Apple ID和开发者账号进行登录。
    登录成功后,Transporter会连接到你的App Store Connect账户。
    3.准备IPA文件
    将需要上传的IPA文件准备好,确保其文件已经通过Xcode或其他工具正确生成并签名。
    4.拖拽IPA文件到Transporter
    将准备好的IPA文件拖入Transporter的上传窗口。Transporter支持一次拖入多个IPA文件,非常适合需要批量上传的场景。
    确保IPA文件的名称、版本号、Bundle ID等信息正确无误。
    5.点击“Deliver”上传IPA
    文件拖入后,点击右下角的“Deliver”按钮,开始上传IPA到App Store Connect。
    Transporter会自动检查IPA文件的完整性、签名、证书等信息。如果有问题,会提示相应的错误信息。
    6.查看上传状态
    上传过程中,Transporter会显示进度条,我们可以随时查看上传状态。
    上传完成后,Transporter会提供成功或失败的反馈。如果成功,我们就可以登录App Store Connect,查看上传的应用记录。
    常见问题与解决方案
    签名错误:如果上传时遇到签名问题,请检查IPA文件是否已经使用正确的证书签名。如果证书有误,Transporter会提示相关错误信息。
    网络问题:Transporter依赖稳定的网络连接,如果上传中断,请确保网络通畅并重新尝试上传。
    优缺点
    优点:独立于Xcode,特别适合不使用Xcode的开发者,支持批量上传,操作页面简洁明了。对于跨平台开发者非常友好。
    缺点:相比Xcode直接上传,Transporter的使用可能需要额外的步骤,尤其对于新手而言。
    结语
    将IPA文件上传到App Store Connect是iOS应用发布流程中的关键一步。无论你是使用Xcode进行原生开发,还是通过uni-app、Flutter等跨平台框架构建应用,苹果提供了多种上传方式来满足不同场景的需求。Xcode上传适合简单、直接的操作,altool命令行工具则为自动化部署提供了极大的灵活性,而Transporter则是独立于Xcode的批量上传利器。

    开发者可以根据项目的规模、团队需求以及CI/CD集成等实际情况,选择最合适的上传方案,确保高效、顺利地将应用发布到App Store。希望本文的介绍能帮助你更好地理解和掌握这些上传方式,让你的应用上传过程更加顺畅。

    文章来源:https://blog.csdn.net/weixin_39339407/article/details/142829483

  • 一个ios私钥证书可以多个app同时使用

    在苹果开发者中心,ios distribution类型,也就是发布类型的证书,最多只能创建两个,但是这样问题就来了,假如我们4个app,那怎么办呢?能否4个app都使用同一个证书来打包呢?

    答案是可以的,而且必须这样做,因为苹果开发者中心无法创建第三个ios distribution类型的证书, 所以只能也必须多个app共用一个证书。

    不同的app,私钥证书是允许共用的。但是不同的app要创建不同的appId(appId可以理解为包名), 而因为创建证书profile文件的时候,是需要绑定appId的,所以证书profile文件(描述文件)是不允许相同的,假如相同的描述文件,就等于同一个appId了,那么对于苹果开发者中心来说,就等于同一个app了。因此证书profile文件是不允许共用的,而p12格式的私钥证书是允许共用的。

    假如觉得多个不同的团队共用一个证书不安全,可以共用一个cer证书,导出p12证书的时候导出多个,这个是可以实现的,因为p12私钥证书是由cer证书导出的,同一个cer证书,可以导出多次p12证书。

  • Nativefier——将web端程序打包成一个pc端程序(exe文件)?

    Nativefier——将web端程序打包成一个pc端程序(exe文件)?

    介绍

    Nativefier 是一款命令行工具,可以轻松地为任何网站创建 “桌面应用程序”,而无需大费周章。应用程序由 Electron(内核使用 Chromium)封装成操作系统可执行文件(.app、.exe 等),可在 Windows、macOS 和 Linux 上使用。


    笔者试过好几次终于成功了!

    你可以在LINUX服务器上或WIN上来打包,首先要确保已安装了NODE,JS16.9以上!

    安装

    本文以 Windows 为例

    环境要求

    • Windows / macOS 10.13 及以上 / Linux
    • Node.js 16.9 及以上
    • npm 7.10 及以上

    安装 Node.js(带 npm )

    Node.js 是一个开源、跨平台的 JavaScript 运行环境。

    如果你的电脑已经安装了 Node.js 且满足版本要求,你可以跳过这一步。
    点击下面的链接进入 Node.js 官网

    Node.js​nodejs.org

    进入页面后,找到“Download Node.js®”下面的两个按钮,点击第一个,下载 LTS 版本(长期支持版本),下载后进行安装。

    检查环境

    打开 Windows Powershell(Windows 终端),输入

    node -v

    查看是否正常返回 Node.js 的版本

    再输入

    npm -v

    查看是否正常返回 npm 的版本

    若一切正常,则代表 Node.js 和 npm 已正常安装。

    安装 Nativefier

    在终端内输入

    npm install nativefier -g

    -g 参数代表全局安装,必须要加,否则就是安装到当前文件夹中,换个位置就用不了了

    耐心等待一会儿,下载速度取决于你的实际网速,如果遇到错误,则按照终端内输出的提示信息进行操作或在文章下方进行评论,我会看的。

    使用

    基础用法

    建议在自己喜欢的位置新建一个文件夹,用来专门存放用 Nativefier 生成的项目。
    将终端路径指向到你的文件夹后,输入

    nativefier "<value>"

    将“<value>” 替换为你想转换的网址,等待一会儿即可。

    进阶用法

    学会了基本用法后,你还可以为你转换的应用自定义名称和图标等等。

    nativefier "<value 1>" --name "<value 2>" --icon "<value 3>"

    将“<value 1>” 替换为你想转换的网址,
    将“<value 2>” 替换为你想要的名字,
    将“<value 3>” 替换为你想要的图标的文件路径,注意,图标文件必须是 .ico 格式,如果你没有 .ico 格式的图标,那么可以用这个工具进行转换

    在线转换图像文件​www.aconvert.com/cn/image/

    完成

    Nativefier 的安装和使用就介绍到这里,更多用法请到官方 Github 项目上查看。

  • uniapp popup常用弹窗

    uniapp popup常用弹窗

    1. 上、下、左、右、中间弹出层

    <view>
        <button class="button" type="primary" @click="toggle('top')"><text class="button-text">点击触发</text></button>
        <!-- 普通弹窗 -->
        <uni-popup ref="popup" background-color="#fff" @change="change">
            <view class="popup-content" :class="{ 'popup-height': type === 'left' || type === 'right' }">
            <text>popup 内容</text></view>
        </uni-popup>
    </view>
    
    return {
        type: 'center',
    }
    methods: {
        // 显示/关闭弹出层的监听
        change(e) {
            console.log('当前模式:' + e.type + ',状态:' + e.show);
        },
        // type 取值范围:left、right、top、bottom、center
        toggle(type) {
            this.type = type
            this.$refs.popup.open(type) // open 方法传入参数 等同在 uni-popup 组件上绑定 type属性
        },
    }
    
    <style lang="scss">
        @mixin flex {
            /* #ifndef APP-NVUE */
            display: flex;
            /* #endif */
            flex-direction: row;
        }
    
        @mixin height {
            /* #ifndef APP-NVUE */
            height: 100%;
            /* #endif */
            /* #ifdef APP-NVUE */
            flex: 1;
            /* #endif */
        }
        .popup-content {
            @include flex;
            align-items: center;
            justify-content: center;
            padding: 15px;
            height: 50px;
            background-color: #fff;
        }
    
        .popup-height {
            @include height;
            width: 200px;
        }
    </style>
    

    2. 上方成功、失败、警告、信息 提示消息

    <view>
        <button class="button popup-success" @click="messageToggle('success')"><text class="button-text success-text">成功</text></button>
        <!-- 提示信息弹窗 -->
        <uni-popup ref="message" type="message">
            <uni-popup-message :type="msgType" :message="messageText" :duration="2000"></uni-popup-message>
        </uni-popup>
    </view>
    
    return {
        msgType: 'success',
        messageText: '这是一条成功提示',
    }
    methods: {
        // type 取值范围:success、error、warn、info
        messageToggle(type) {
            this.msgType = type
            this.messageText = `这是一条${type}消息提示`
            this.$refs.message.open()
        },
    }
    
    <style lang="scss">
        @mixin flex {
            /* #ifndef APP-NVUE */
            display: flex;
            /* #endif */
            flex-direction: row;
        }
        .button {
            @include flex;
            align-items: center;
            justify-content: center;
            flex: 1;
            height: 35px;
            margin: 0 5px;
            border-radius: 5px;
        }
        .button-text {
            color: #fff;
            font-size: 12px;
        }
        .popup-success {
            color: #fff;
            background-color: #e1f3d8;
        }
        
        .popup-warn {
            color: #fff;
            background-color: #faecd8;
        }
        
        .popup-error {
            color: #fff;
            background-color: #fde2e2;
        }
        
        .popup-info {
            color: #fff;
            background-color: #f2f6fc;
        }
        .success-text {
            color: #09bb07;
        }
        
        .warn-text {
            color: #e6a23c;
        }
        
        .error-text {
            color: #f56c6c;
        }
        
        .info-text {
            color: #909399;
        }
        
    </style>
    

    3. confirm 对话框弹窗

    <view>
        <button class="button popup-success" @click="dialogToggle('success')"><text class="button-text success-text">成功</text></button>
        <!-- 提示窗示例 -->
        <uni-popup ref="alertDialog" type="dialog">
            <uni-popup-dialog :type="msgType" cancelText="关闭" confirmText="同意" title="通知" content="欢迎使用 uni-popup!" @confirm="dialogConfirm"
                @close="dialogClose"></uni-popup-dialog>
        </uni-popup>
    </view>
    
    return {
        msgType: 'success',
        messageText: '这是一条成功提示',
    }
    methods: {
        // type 取值范围:success、error、warn、info
        dialogToggle(type) {
            this.msgType = type
            this.$refs.alertDialog.open()
        },
        // 确认
        dialogConfirm() {
            console.log('点击确认')
            this.messageText = `点击确认了 ${this.msgType} 窗口`
        },
        // 关闭
        dialogClose() {
            console.log('点击关闭')
        },
    }
    
    <style lang="scss">
        @mixin flex {
            /* #ifndef APP-NVUE */
            display: flex;
            /* #endif */
            flex-direction: row;
        }
        .button {
            @include flex;
            align-items: center;
            justify-content: center;
            flex: 1;
            height: 35px;
            margin: 0 5px;
            border-radius: 5px;
        }
        .button-text {
            color: #fff;
            font-size: 12px;
        }
        .popup-success {
            color: #fff;
            background-color: #e1f3d8;
        }
        
        .popup-warn {
            color: #fff;
            background-color: #faecd8;
        }
        
        .popup-error {
            color: #fff;
            background-color: #fde2e2;
        }
        
        .popup-info {
            color: #fff;
            background-color: #f2f6fc;
        }
        .success-text {
            color: #09bb07;
        }
        
        .warn-text {
            color: #e6a23c;
        }
        
        .error-text {
            color: #f56c6c;
        }
        
        .info-text {
            color: #909399;
        }
    </style>
    

    4. prompt 输入框弹窗

    <view>
        <button class="button" type="primary" @click="inputDialogToggle"><text class="button-text">输入对话框</text></button>
        <!-- 输入框示例 -->
        <uni-popup ref="inputDialog" type="dialog">
            <uni-popup-dialog ref="inputClose"  mode="input" title="输入内容" value="对话框预置提示内容!"
                placeholder="请输入内容" @confirm="dialogInputConfirm"></uni-popup-dialog>
        </uni-popup>
    </view>
    
    return {
        value: '',
    }
    methods: {
        inputDialogToggle() {
            this.$refs.inputDialog.open()
        },
        dialogInputConfirm(val) {
            uni.showLoading({
                title: '3秒后会关闭'
            })
        
            setTimeout(() => {
                uni.hideLoading()
                console.log(val)
                this.value = val
                // 关闭窗口后,恢复默认内容
                this.$refs.inputDialog.close()
            }, 3000)
        },
    }
    
    <style lang="scss">
        @mixin flex {
            /* #ifndef APP-NVUE */
            display: flex;
            /* #endif */
            flex-direction: row;
        }
        .button {
            @include flex;
            align-items: center;
            justify-content: center;
            flex: 1;
            height: 35px;
            margin: 0 5px;
            border-radius: 5px;
        }
        .button-text {
            color: #fff;
            font-size: 12px;
        }
    </style>


  • 【uniapp】十分钟带你封装uniapp的api请求

    【uniapp】十分钟带你封装uniapp的api请求

    封装前的准备

    先在项目目录上右键 – 新建目录(用于存放封装的API请求文件)

    • 名称大家可以随意取,我这里给的是request

    目录新建完成之后,还需要至少两个js文件

    • index.js 封装get、post请求,接收参数并返回数据
    • api.js 封装后台接口,便于页面调用和后期维护

    为啥这里说的是至少两个js文件呢?那是因为可能因为权限的原因,亦或者模块的分类等,可以把api.js文件给拆分出去,按照不同的权限、模块来进行分类,最终可以通过一个总的js文件合并,这样更利于后期维护。

    封装第一步:index.js

    定义请求参数

    • 必备参数:url、method、header、data
    • 可选参数:hideLoading
    • export default class Request {
    http(param) {
    let url = param.url;
    let method = param.method;
    let header = param.header || {};
    let data = Object.assign(param.data || {});
    let hideLoading = param.hideLoading || false;
    // 第一步的代码均在此处展示,后面示例代码就不写外层 class 和 http方法了。
    ....
    }
    }
    • hideLoading主要是后面用于显示加载toast状态的

    请求地址

    • 其实请求地址可以单独封装成一个js文件的,比如开发环境、正式环境、测试环境都用不同的请求地址。
    let requestUrl = 'https://www.juejin.cn/' + url;

    请求方式

    • 此处仅封装GET、POST两种方式,其他的请求方式可以根据需求去进行封装
    if (method) {
    if (method == "POST") {
    header = Object.assign({
    'content-type': "application/x-www-form-urlencoded"
    }, param.header)
    } else {
    header = Object.assign({
    'content-type': "application/json"
    }, param.header)
    }
    }
    • method参数必须是大写的哦~(微信小程序和uniapp均有文档查阅)
    • 将content-type和用户传递的header数据进行合并,组成一个新的header参数

    请求加载(这里是可选的配置项)

    • 数据配置完成后,可以给用户一个loading的等待效果
    if (!hideLoading) { uni.showLoading() }

    返回Promise

    • 通过promise返回数据,可以在页面上请求接口的时候,直接使用.then来拿到数据(也算是目前前端常用的写法了吧)
    return new Promise((resolve, reject) => {
    uni.request({
    url: requestUrl,
    data: data,
    method: method,
    header: header,
    success: (res) => {
    // 下面会直接写请求成功的代码
    ......
    },
    fail: (err) => {
    // 下面会直接写请求失败的代码
    ......
    },
    })
    })
    • 在promise中写上请求方法,并接收上面定义的参数
    // success里面的逻辑代码
    // 如果有显示loading的话,可以在这里选择隐藏
    if (!hideLoading) {
    uni.hideLoading();
    }
    // 判断请求是否成功(通过后端接口返回的状态进行判断)
    // code:0 即成功,不为 0 的话就是请求错误/失败
    if(res.data.code === 0){
    resolve(res.data)
    return true
    } else {
    if(res.data.code === -1){
    // 这里是由于token过期导致的错误码
    // 可以直接跳转到login页面,也可以直接刷新token
    uni.navigateTo({
    url: '/pages/login/login'
    })
    }
    // 其他错误时,直接通过toast提示
    uni.showToast({
    title:res.data.msg,
    icon:'none'
    })
    return false;
    }
    // fail里面的逻辑代码
    // 如果有显示loading,同样需要隐藏
    if (!hideLoading) {
    uni.hideLoading();
    }
    return false;

    封装第二步:api.js

    引用封装好的index.js文件

    import Request from './index.js' let request = new Request().http

    get、post请求方法

    function get(url, data, hideLoading, header) {
    return request({
    url: url,
    method: 'GET',
    data: data,
    header: header
    })
    }
    
    function post(url, data, hideLoading, header) {
    return request({
    url: url,
    method: 'POST',
    data: data,
    header: header,
    hideLoading: hideLoading,
    })
    }

    封装api对象

    • 通过上面的方法,来确定请求类型
    let api = {
    login: data => post('loginapi', data, true, true)
    }
    
    export default api;
    • 为了能够在全局进行使用,需要在main.js文件中进行配置
    • $http是自定义名称,可以根据自己的需要去修改
    • 在引入文件中,我们只需要引入api.js即可
    import api from "./request/api.js"
    Vue.prototype.$http = api;

    使用方法

    onLoad(){
    this.$http.login().then(res=>{
    console.log(res)
    })
    }
    • 在页面上使用的时候,直接通过this.$http找到对应的api方法
    • 如果需要传参,可以在login方法中直接传递login({name: ‘xxx’, sex: ‘yyy’})

    总结

    在uniapp中封装请求方法,其实和vue里面的axios封装方式差不多,通过一次封装,改变之后的开发模式和维护成本是很重要的。

    由于兼职的后端还没开始写接口,所以就不在这里展示具体的请求数据了,大家可以自行尝试一下。

    uniapp常用组件及api使用方法:https://blog.csdn.net/weixin_43664855/article/details/131409406

    如何调用API:https://blog.csdn.net/p_s_p/article/details/130880583

    天气参考:https://blog.csdn.net/Red_sevenWord/article/details/135019087

    uni-app 超详细教程(一)(从菜鸟到大佬):https://blog.csdn.net/zhousenshan/article/details/131351310?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-4-131351310-blog-128123590.235^v43^pc_blog_bottom_relevance_base2&spm=1001.2101.3001.4242.3&utm_relevant_index=7

    uni-app 超详细教程(二)(从菜鸟到大佬):

    https://blog.csdn.net/m0_64875238/article/details/128123590

    文章来源:https://juejin.cn/post/7249228528573694013

  • apk空白包签名-应用认领

    apk空白包签名-应用认领

    APK空白包签名是一种常见的应用程序打包技术,它允许开发者在没有实际的应用程序代码和资源的情况下生成一个空的APK文件,并对其进行签名。在这个教程中,我们将介绍APK空白包签名的原理和详细步骤。

    1. 原理:

    APK空白包签名的原理是利用Android应用程序的打包机制。一个APK文件实际上是一个ZIP文件,里面包含了应用程序的代码、资源、配置文件等等。在签名过程中,我们只需要对APK文件本身进行签名,而不必关心其中的具体内容。

    2. 详细步骤:

    下面是一个详细的APK空白包签名步骤:

    – 准备一个空的APK文件,可以使用任何ZIP工具创建一个空的ZIP文件,并将后缀改为`.apk`。

    – 创建一个密钥库文件,可以使用Java的keytool工具创建一个密钥库文件,命令如下:

    “`

    keytool -genkey -v -keystore my-release-key.keystore -alias my-alias -keyalg RSA -keysize 2048 -validity 10000

    “`

    这个命令将生成一个名为`my-release-key.keystore`的密钥库文件,并指定一个别名和一个有效期。

    – 使用jarsigner命令对空APK文件进行签名,命令如下:

    “`

    jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore my-app.apk my-alias

    “`

    这个命令将使用之前生成的密钥库文件对空APK文件进行签名,并指定签名算法和摘要算法。

    – 使用zipalign工具优化已签名的APK文件,命令如下:

    “`

    zipalign -v 4 my-app-signed.apk my-app-final.apk

    “`

    这个命令将调整APK文件的对齐方式,使其在安装时能够更高效地使用存储空间。

    以上就是APK空白包签名的详细步骤。需要注意的是,为了保证签名的安全性,我们应该在生成密钥库文件时使用足够强大的密码,并将其妥善保存。

    3. 使用场景:

    APK空白包签名常用于一些特定的开发和测试场景,例如在开发过程中测试与签名相关的逻辑,或为应用程序生成一个空的APK文件以供其他开发者进行二次开发。此外,一些自动化测试工具也可能使用APK空白包签名来处理APK文件。

    总结:

    APK空白包签名是一种常见的应用程序打包技术,它利用Android应用程序的打包机制,允许开发者在没有实际代码和资源的情况下生成一个空的APK文件,并对其进行签名。这个技术在一些开发和测试场景中非常有用,但在正式发布应用程序时不应使用空白包签名。

    实在不行,就用第三方工具:https://yuanjkeji.com/ios-upload/app/list

  • IOS/安卓应用APP备案获取App特征信息填写指导

    IOS/安卓应用APP备案获取App特征信息填写指导

    进行阿里云App备案服务申请时,您需要填写App的相关特征信息。本文为您介绍安卓平台、iOS平台App特征信息的获取方法。

    基础概念

    概念解释
    包名(安卓应用标识符)APK包名是Android应用程序的唯一标识符。例:com.alibaba.aliyun。
    Bundle ID(iOS应用标识符)Bundle ID是iOS应用程序的唯一标识符。例:com.aliyun.beian.app。
    数字证书数字证书是一个经权威授权机构数字签名,包含公开密钥的拥有者信息以及公开密钥的文件,是由权威机构颁发的可信凭证。
    数字签名数字签名采用非对称密钥生成算法,会生成一对密钥:私钥和公钥。发送方使用私钥加密摘要来进行签名,接收方必须使用对应的公钥才能进行解密。
    数字摘要数字摘要又称数字指纹,是使用Hash函数将待加密明文转化得到的一串固定长度密文。常见的摘要算法有 MD5、SHA-1、SHA-256等。

    安卓应用获取App特征信息指导

    包名、公钥和签名MD5获取方式有多种,本文以使用JadxGUI工具获取为例。

    1. 下载JadxGUI工具:下载安装完成后,使用此工具打开apk包。
    2. 公钥与签名MD5值获取:查找文件APK signature中模数(公钥)和MD5签名。image.png
    3. 包名获取:查找资源文件下AndroidManifest.xml中的package属性对应信息。

    iOS应用获取App特征信息指导

    1. 访问https://developer.apple.com/cn/,使用App对应的iOS开发者账号登录。
    2. Bundle ID获取:在计划资源中查看标识符,其中IDENTIFIER列对应的就是Bundle ID。image.pngimage.png
    3. 公钥与签名SHA1值获取:在计划资源中查看证书,进入证书后,下载对应App证书。通过查看详细信息,获取公钥(公共密钥)和签名SHA1值(SHA-1)。image.pngimage.png
      • 公钥(公共密钥)image.png说明如果公共密钥显示不完整,您可先单击省略号,如果省略号仍然打不开或不显示,直接复制公共密钥省略号前面显示出的数据进行填写即可。
      • 签名SHA1值(SHA-1)

    参考链接:https://help.aliyun.com/zh/icp-filing/fill-in-app-feature-information

    https://pmself.com/3085.html